January 20

On Saturday, 20 January 2024 at 09:00:22 UTC, Danilo wrote:

>

I thought this should easily work, but I was wrong:

[...]

Those actually would not be aliases but more "parameter-less expression macros".

In order to make those aliases working, it would be necessary to monomorphize and recontextualize the source expression for each use:

struct Vec3 {
    Vec2 v;
    alias x = v.x; // cannot contextualize, no "this"
}

Vec3 v1, v2;

v1.x = 0; // -> create v1.v.x, contextualize
v2.x = 0; // cannot reuse, "this" has changed
          // you have to copy and recontextualize

So you think that it's nice but it's actually more like a mixin.

An old PR would have allowed that but quickly a reviewer noticed that these are not classic aliases, but something more complex, bringing possible issues.

On top of that, as there's no "scope", contextualization can lead to ambiguous situations, reproducing the problem of what is called "unhygienic macros"... although for dot chains, that should not happen too much 🤞😐🤞.

January 20

On Saturday, 20 January 2024 at 20:48:46 UTC, Basile B. wrote:

>

Those actually would not be aliases but more "parameter-less expression macros".

Yeah, it is just intuitive to assume that alias can be used to
give an additional alias name to something and then access
the entity using the alias name.

It's just intuitive, nothing special i tried here. ;)

January 20

On Saturday, 20 January 2024 at 09:00:22 UTC, Danilo wrote:

>

Can't alias targets be used in method bodies?

In the method/constructor parameters it's working as expected. But not inside the bodies?

alias is always about a symbol. It is not about an expression. Yes, in some cases (such as template parameters) you can alias an expression. This is not the same thing.

So when you do:

alias x = v.x;

What you are doing is saying x is an alias to Vec2.x, the symbol. The v plays no part in it except to be a namespace -- it does not help clarify which x you are talking about.

Why does it work for normal members? To be clear, I'm talking about:

struct S
{
   int x;
   alias x2 = x;
}

It's actually the same thing thing as your v.x example! x2 is an alias to the symbol S.x, not to the instance variable this.x. It works because when you access it, you are accessing it through the instance variable, and the compiler says "aha! the symbol x on the instance, I know how to access that". But when you access the symbol Vec2.x on a Vec3, it doesn't know how to resolve that without a (proper) instance (remember, the v is just used for namespacing, not directing how to access the alias).

So how do you do it?

struct Vec3
{
   Vec2 v;
   ref x() => v.x;
   ref y() => v.y;
}

It's not perfect, as taking the address of x will yield a delegate, and not a pointer to the member, but it's the best you can do.

Now, you might wonder, why does alias work when passed to a template function? Because the compiler adds a hidden context parameter, which then tells it how to access the variable. This is a feature which does not apply everywhere alias is used -- you are not always calling a function where a context parameter can be passed.

-Steve

January 20

On Saturday, 20 January 2024 at 22:16:35 UTC, Steven Schveighoffer wrote:

>

So how do you do it?

struct Vec3
{
   Vec2 v;
   ref x() => v.x;
   ref y() => v.y;
}

It's not perfect, as taking the address of x will yield a delegate, and not a pointer to the member, but it's the best you can do.

Thanks Steven! Of course you all are able to concentrate on the
details of how it is implemented, because you work on that level every day.

If you step back to see the bigger picture, it is very intuitive to write:

alias x = v.x;
alias y = this.v.y;

It means giving an alias name to an entity, and I think it's not hard to understand that.
It's just logical in a broader sense, when you look at the bigger picture. ;)

January 20

On Saturday, 20 January 2024 at 22:25:35 UTC, Danilo wrote:

>

If you step back to see the bigger picture, it is very intuitive to write:

alias x = v.x;
alias y = this.v.y;

It means giving an alias name to an entity, and I think it's not hard to understand that.
It's just logical in a broader sense, when you look at the bigger picture. ;)

alias is already reserved for special purposes in D, so we probably
need a new keyword for this: pseudonym

pseudonym x = v.x;
pseudonym y = this.v.y;

Don't take that too seriously, just came to my mind... lol ;)

January 20

On Saturday, 20 January 2024 at 22:25:35 UTC, Danilo wrote:

>

Thanks Steven! Of course you all are able to concentrate on the
details of how it is implemented, because you work on that level every day.

If you step back to see the bigger picture, it is very intuitive to write:

alias x = v.x;
alias y = this.v.y;

It means giving an alias name to an entity, and I think it's not hard to understand that.
It's just logical in a broader sense, when you look at the bigger picture. ;)

I agree that it's intuitive to do. It just doesn't do the thing you are expecting. It's a code smell in D.

I even filed an issue on it. https://issues.dlang.org/show_bug.cgi?id=16123

-Steve

January 21

On Saturday, 20 January 2024 at 22:41:30 UTC, Steven Schveighoffer wrote:

>

On Saturday, 20 January 2024 at 22:25:35 UTC, Danilo wrote:

>

If you step back to see the bigger picture, it is very intuitive to write:

alias x = v.x;
alias y = this.v.y;

It means giving an alias name to an entity, and I think it's not hard to understand that.
It's just logical in a broader sense, when you look at the bigger picture. ;)

I agree that it's intuitive to do. It just doesn't do the thing you are expecting. It's a code smell in D.

I even filed an issue on it. https://issues.dlang.org/show_bug.cgi?id=16123

-Steve

Works in Neat, btw! :) You can even alias expressions.

For example, https://github.com/Neat-Lang/neat/blob/master/src/neat/base.nt#L747

January 21

On Sunday, 21 January 2024 at 04:50:03 UTC, FeepingCreature wrote:

>

Works in Neat, btw! :) You can even alias expressions.

For example, https://github.com/Neat-Lang/neat/blob/master/src/neat/base.nt#L747

Expressions aliases have a lot of problems when postfixes are involved.

Assuming Neat grammar is similar to D, things like

alias memberCall = member.call();

would give, as used in the source code

context.memberCall;

which is then lowered to

context.(member.call());

while it should be

(context.member).call();

So it's no only the unintentional capture problem here, it also now about precedence. Unless you'be already aware of the problem (or maybe you'd use your macro system ?) I have more examples here.

January 21

On Saturday, 20 January 2024 at 20:25:21 UTC, Max Samukha wrote:

>

On Saturday, 20 January 2024 at 15:55:13 UTC, Paul Backus wrote:

>

alias this is used as a fallback for member lookup when no symbol with the requested name exists. Since you declared a symbol named x in S2, there is no need to fall back to alias this when attempting to look up S2().x.

Arguable but I don't have the energy to argue. Let it be.

I've filed a bug report for this, just in case https://issues.dlang.org/show_bug.cgi?id=24350

January 21

On Sunday, 21 January 2024 at 05:54:15 UTC, Basile B. wrote:

>

Assuming Neat grammar is similar to D, things like

alias memberCall = member.call();

would give, as used in the source code

context.memberCall;

which is then lowered to

context.(member.call());

while it should be

(context.member).call();

So it's no only the unintentional capture problem here, it also now about precedence. Unless you'be already aware of the problem (or maybe you'd use your macro system ?) I have more examples here.

I have a hard time understanding what problem you're describing, but it's probably fine? Expression aliases are evaluated in the context of the declaration site, not the call site. This doesn't involve the grammar at all.