December 03
On 12/3/2024 7:17 AM, Max Samukha wrote:
> // this is needed because we still cannot express "local to static foreach".

That's because static foreach will become fairly useless if it introduced a scope. (Same as for static if.) However, you can still add { } to make a scope:

```
{ static foreach(...) { } }
```
Or:
```
static foreach (...) {{ }}
```
December 04
On 04/12/2024 11:12 AM, Walter Bright wrote:
> Koenig lookup? I ran away, far away, from that, after implementing it for C++.
> 
> It's a nightmare.

I got a bit of a chuckle out of that.

You've been very careful with symbol lookup, its why I was pretty careful when designing my proposal for replacing alias this.

Keep things nice and simple, by following the inheritance hierarchy only!

December 04
On 12/3/24 23:16, Walter Bright wrote:
> On 12/3/2024 7:17 AM, Max Samukha wrote:
>> // this is needed because we still cannot express "local to static foreach".
> 
> That's because static foreach will become fairly useless if it introduced a scope. (Same as for static if.) However, you can still add { } to make a scope:
> 
> ```
> { static foreach(...) { } }
> ```
> Or:
> ```
> static foreach (...) {{ }}
> ```

It does introduce a scope for the loop variables, there is just no way to add your own temporary variables to that scope.

I had this implemented as the `__local` storage class, but I did not include it in the DIP proposal to avoid bikeshedding over syntax delaying the entire `static foreach` implementation:

https://github.com/dlang/dmd/commit/bac3426f9881e4a591df229423475efc6c3e0918

static foreach(i;0..10){
    __local enum tmp = i*i;
   // use tmp here
} // no redefinition error


There was also `__previous`, that allowed to access the `__local` variables from the previous iteration, allowing more imperative-style code:

https://github.com/dlang/dmd/commit/6c2f4b9c41cef5895efd3c1161920a47ed0b6464

static foreach(i;0..100){
    enum next_i = i+1;
    static if(i){
        static assert(__previous.i == i-1);
        static assert(__previous.next_i == i);
    }
}


It's a few lines of code to make that work though, the storage class exists, it's just not accessible to user code.

People have been using mixin templates to tuck away their loop-body-local variables ever since, due to the way scoping works for mixin templates (if you mix in the same mixin template multiple times unnamed into the same scope, the declarations in them do not conflict, but may become inaccessible from outside the mixin template instance.) This is what that comment was on.
December 04
On 12/3/24 23:12, Walter Bright wrote:
> Koenig lookup? I ran away, far away, from that, after implementing it for C++.
> 
> It's a nightmare.
Sure, but the question was, how do you do actually do the serialization via introspection.
December 04
On 04/12/2024 3:32 PM, Timon Gehr wrote:
> I had this implemented as the |__local| storage class, but I did not include it in the DIP proposal to avoid bikeshedding over syntax delaying the entire |static foreach| implementation:

I'm trying to come up with alternative syntax.

Everything so far, a scope guard, an attribute, everything is coming up as having worse trade offs.

It may not feel right, but it has pretty good trade offs I think.

But yeah I'd quite like having this.

December 04
On 12/3/24 12:55, Manu wrote:
> Maybe someone has a pattern for doing this kind of thing...

There are a couple solutions that look okay already, but basically, importing into any unordered scope works, e.g.

```d
module default_serialise;
ubyte[] serialise(T)(T arg)if(!is(T==struct)){ return [1]; }
```

```d
module user_code;
struct S{}
ubyte[] serialise(S){ return [2]; }
```

```d
import default_serialise;

void main(){
    import std;
    static struct Dummy{
        import default_serialise: serialise;
        import user_code: serialise;
    }
    import user_code;
    writeln(Dummy.serialise(1)); // [1]
    writeln(Dummy.serialise(S())); // [2]
}
```

You can also use a dummy template scope (template Dummy(), and then `Dummy!().serialise`).

I dislike function-local import semantics quite a bit as they do not follow the well-thought-out overloading rules that apply to other imports.
December 03
Back before I ended work on C++, a number of C++ Illuminati told me privately that ADL was a mistake. Things may have changed since then, and I don't know about that.
December 03
On 12/3/2024 6:39 PM, Timon Gehr wrote:
> Sure, but the question was, how do you do actually do the serialization via introspection.

As I haven't attempted that, I might suggest use of:

1. interfaces

2. output ranges (sinks)
December 04
On 04/12/2024 8:29 PM, Walter Bright wrote:
> Back before I ended work on C++, a number of C++ Illuminati told me privately that ADL was a mistake. Things may have changed since then, and I don't know about that.

https://en.cppreference.com/w/cpp/language/adl

Defects:

CWG 33	C++98
CWG 90	C++98
CWG 239	C++98
CWG 997	C++98
CWG 1690	C++98 C++11
CWG 1691	C++11
CWG 1692	C++98
CWG 2857	C++98

That list sure gives confidence!

December 03
Thanks for the clarification