October 28, 2021
On Thursday, 28 October 2021 at 04:05:09 UTC, SealabJaster wrote:
> Throwing out another DOA idea but: Would a special `@version()` UDA manage to get anywhere?
>
> For example
>
> ```d
> @version(1)
> auto splitter(...)(...){}
>
> @version(2)
> auto splitter(...)(...){}
> ```
>
> And then introduce syntax to specify which version to use?
>
> ```
> import std.algorithm : splitter@2; // as an example.


You could just as well do

auto splitter_v1.....
auto splitter_v2.........

import std.algorithm: splitter = splitter_v2

today.
October 28, 2021
On Thursday, 28 October 2021 at 13:22:46 UTC, Adam D Ruppe wrote:
> On Thursday, 28 October 2021 at 08:50:31 UTC, Robert burner Schadek wrote:
>> I think this version schema is fundamentally wrong and looks to me like a quick way to the D1 standard library mess.
>
> The problem there was you couldn't use the two together. The point of this versioning thing is to try to come up with a scheme where you CAN use them together.

"can" is one thing, but can you do it in a way with that is undetectable? Because if users can detect it, then it is likely to lead to incompatibility-issues. Isn't it?

Since D has the "does it compile" feature, it will be very difficult to prove that the design is sound and that a package, that makes assumptions about V1 types, is not going to be affected down the road.




October 28, 2021
On Thursday, 28 October 2021 at 13:22:46 UTC, Adam D Ruppe wrote:
> The problem there was you couldn't use the two together. The point of this versioning thing is to try to come up with a scheme where you CAN use them together.

hm fair enough, but very likely still a mess in the middle run.

What about a compiler daemon library thing that you could write small programs for that converts the use of the deprecated feature/function into the up to date version.

Think small scale python 2to3 script, but programmable and something that actually understands the language.

That way, when you break and api or the language, you provide a fix script for each.
Apply them one after the other and you breaking change isn't technically breaking anything anymore.

So that way when you update your old program that used D 120.4.7 to 202.7.2 you rust run the 82 batches of fix up scripts and move on with your life.

Did somebody said database migrations ....
October 28, 2021
On Thursday, 28 October 2021 at 13:34:14 UTC, Ola Fosheim Grøstad wrote:
> "can" is one thing, but can you do it in a way with that is undetectable?

No, but I also don't think that matters. You need to pick a new version so then you expect things to be different.

There's always problems. You need to pick which ones you care about. There's two things to think about:

1) the hassle of updating with breaking changes
2) the incompatibility of diamond dependencies

A diamond dependency is when your app depends on libA which depends on thingv1 and also on libB which depends on thingv2.

For #1, I'd just really provide a migration path. If it is too much of a pain, version lock what you already have. But you'll probably lead to a diamond dependency eventually anyway as not everyone locks.

Let's look at some solutions.

With dub's version scheme, this is an error. When it detects this, dub stops building.

With the SAOC mangling scheme proposal, you're liable to have runtime crashes when you import one version of a type yet pass it to a library that needs another version - ABI mismatch beyond what mangles can see. The idea to add type layout to the mangle would turn this from a runtime crash into linker error, but it still fails.

Moving the version difference up to the module level is liable to create compile errors of the type "cannot pass X to function expecting argument X" (where X is v1 in one case and v2 in the other case). You can actually solve this with a runtime conversion, or making the compatibility layer check or whatever. It won't "just work" but since it is manageable it is my preference.

But then changing versions means updating imports to opt into it... which again i say "meh" but some people can't stand. It also means potential duplication which can be a hassle but again it is something you can manage so again "meh".

And sure maybe you can detect a change in the compatibility layer with reflection. Maybe some types won't convert back and forth. But... so be it. My view is a compatibility layer is to bridge the gap between the inevitable migration. Again, for an individual, you can just version lock. It is really only the diamond problem that is blocked.... and there, if they don't migrate eventually it will just get worse anyway, but they might not all migrate at the same time.

And if a lib never updates and it is hard incompatible the whole time? Just use a better lib.
October 28, 2021

On 10/28/21 7:30 AM, Ogi wrote:

>

On Tuesday, 26 October 2021 at 06:05:08 UTC, bauss wrote:

>

The only problem I see when versioning the standard library is that some packages will rely on specific versions of the standard library and it could make it difficult to use packages that rely on different versions of the standard library.

You’re saying it like it’s not a big deal but I’m afraid it’s going to be a huge source of pain. Imagine not being able to get some DateTime, or Complex, or File from one package and pass it to another because one depends on std1 and the other depends on std2. Or imagine dealing with different versions of the same exception class. It appears to me that versioning the standard library is a bullet train straight to dependency hell.

Yes, this is a part that is not being considered. We have clues as to how hellish it will be with experience in using Windows DLLs which have their own independent copy of the runtime (and all the "same but not same" TypeInfo instances).

And there is the problem with string actually being the same type in both libraries but doing completely different things (autodecoding).

I'm wondering, if we did things like you do database migrations, if it might help (with the former problem). That is, if you pass a std.stdio.File to a function accepting a std2.stdio.File, the compiler is given a way to convert the internals/state. Something like that might make things palatable.

-Steve

October 28, 2021
On Thursday, 28 October 2021 at 14:12:44 UTC, Steven Schveighoffer wrote:
> is, if you pass a `std.stdio.File` to a function accepting a `std2.stdio.File`, the compiler is given a way to convert the internals/state.

Well, if there was implicit construction, you could always make a constructor for the one File that accepts the other and converts.

Of course, the user could also just call a transition function you define.

If you're willing to do a little work you can make it happen.
October 28, 2021
On Thursday, 28 October 2021 at 13:27:03 UTC, Adam D Ruppe wrote:
> You could just as well do
>
> auto splitter_v1.....
> auto splitter_v2.........
>
> import std.algorithm: splitter = splitter_v2
>
> today.

Aha, so you could!
October 28, 2021

On 10/28/21 10:18 AM, Adam D Ruppe wrote:

>

On Thursday, 28 October 2021 at 14:12:44 UTC, Steven Schveighoffer wrote:

>

is, if you pass a std.stdio.File to a function accepting a std2.stdio.File, the compiler is given a way to convert the internals/state.

Well, if there was implicit construction, you could always make a constructor for the one File that accepts the other and converts.

This is going to still be a bit painful. I was thinking for more compiler help.

For example, if you had:

import lib1; // uses Phobos 1 File
import lib2; // uses Phobos 2 File

void foo()
{
   lib2.funAcceptingFile(lib1.funProducingFile());
}

This is going to have an error, instead you need to do:

void foo()
{
   import std2.stdio : File;
   lib2.funAcceptingFile(File(lib1.funProducingFile()));
}

Which isn't horrible, but could cause problems if you have both symbols. I also imagine the error to be comical:

Error: No overload of funAcceptingFile accepts arguments (File). Possible overloads:
void funAcceptingFile(File)

If the compiler just figured out the conversion is possible on the original code (by being told how it can do that), then there's no need to manually do this conversion.

>

If you're willing to do a little work you can make it happen.

Sure, with a little work, you can make anything happen. But will people be willing to do that work? If not, then won't we just end up with a lot of effort to build and maintain something nobody uses? I personally would rather just use the v2 exclusively, and eliminate any usage of v1.

-Steve

October 28, 2021
On Thursday, 28 October 2021 at 14:01:57 UTC, Adam D Ruppe wrote:
> On Thursday, 28 October 2021 at 13:34:14 UTC, Ola Fosheim Grøstad wrote:
>> "can" is one thing, but can you do it in a way with that is undetectable?
>
> No, but I also don't think that matters. You need to pick a new version so then you expect things to be different.

Hm, not sure if I follow... For this to work well I think you would need to have a different culture and a type system that focus more on abstract interfaces.

When programmers write code for a particular language/library/runtime/compiler they tend to make assumptions, that they probably shouldn't have. Like implementation specific aspects of how the runtime behaves or how classes are laid out and serialized.

Let's say you have a file cache package that assumes V1 file objects. It does use templated parameters so it actually accepts anything (duck typing) with the right interface. In the docs it says you have to always use objects from the standard lib. But there is no actual type checking that forces it to be V1, so the outcome could be unpredictable when handed V7 objects, as the package is tailored to V1 (making assumptions that are specific to V1).

One might claim that people should not write ugly code, but most applications of scale does contain ugly code.

October 28, 2021
On Thursday, 28 October 2021 at 14:30:38 UTC, Steven Schveighoffer wrote:
> On 10/28/21 10:18 AM, Adam D Ruppe wrote:
> if there was implicit construction
>
> This is going to still be a bit painful. I was thinking for more compiler help.

well, if there was implicit construction, the compiler would do that conversion for you, c++ style.

but yeah today you can import the other thing and do the conversion yourself....

> I personally would rather just use the v2 exclusively, and eliminate any usage of v1.

I think that ought to be the goal. You'd keep the v1 stuff around just as a temporary bridge to give some flexibility to schedule that transition, but realistically, the transition is inevitable unless you want to lock everything (which is always an option of course).