July 08

On Monday, 8 July 2024 at 03:26:32 UTC, IchorDev wrote:

>

On Sunday, 7 July 2024 at 19:42:25 UTC, Nick Treleaven wrote:

>

However, that doesn't seem to help for an implicit struct construction expression.

I don’t see why a similar solution couldn’t work?

Vladimir's idea is for an identifier to have its own type. When omitting the struct type, there is no identifier. So that idea doesn't have a bearing on being able to do that.

MyStruct x;
x = _(args); // type identifier not present

BTW it would be nice to be able to omit the class type in a NewExpression too:

MyClass obj;
obj = new _(args);
July 08

On Monday, 8 July 2024 at 07:02:34 UTC, ryuukk_ wrote:

>

On Sunday, 7 July 2024 at 19:07:10 UTC, Nick Treleaven wrote:

>

On Saturday, 6 July 2024 at 08:04:36 UTC, ryuukk_ wrote:

>

MySelfExplanatoryType flag = MySelfExplanatoryType.A | MySelfExplanatoryType.B MySelfExplanatoryType.C;

You could write:

auto flag = { with (MySelfExplanatoryType) return A | B | C; }();

No, this syntax is just bad, it's unreadable and over engineered

It's not great, but it does do what you said the point of the feature was:

>

to avoid repetition and to make code more concise in places that are relevant

I only suggest it for cases when using an alias is not acceptable.

July 08

On Monday, 8 July 2024 at 10:45:22 UTC, Nick Treleaven wrote:

>

On Monday, 8 July 2024 at 07:02:34 UTC, ryuukk_ wrote:

>

On Sunday, 7 July 2024 at 19:07:10 UTC, Nick Treleaven wrote:

>

On Saturday, 6 July 2024 at 08:04:36 UTC, ryuukk_ wrote:

>

MySelfExplanatoryType flag = MySelfExplanatoryType.A | MySelfExplanatoryType.B MySelfExplanatoryType.C;

You could write:

auto flag = { with (MySelfExplanatoryType) return A | B | C; }();

No, this syntax is just bad, it's unreadable and over engineered

It's not great, but it does do what you said the point of the feature was:

>

to avoid repetition and to make code more concise in places that are relevant

I only suggest it for cases when using an alias is not acceptable.

Hence the feature suggestion, because the current solutions are not good

July 08

On Saturday, 6 July 2024 at 02:49:32 UTC, Steven Schveighoffer wrote:

>

The biggest problem with this is -- it breaks all existing knowledge of what this does. It is, for sure, the most natural syntax for this feature. One might argue that $.symbol could mean "global symbol" instead (or something else).

Considering how $ is used in D, that is weird. Given that we have this.x in a class, why not module.x for “global” (i.e. module-scope) stuff?

July 08

On Sunday, 7 July 2024 at 19:07:10 UTC, Nick Treleaven wrote:

>

On Saturday, 6 July 2024 at 08:04:36 UTC, ryuukk_ wrote:

>

The pushback is from people who never got to learn new languages, they believe this is what everyone wants to write

They do not believe that.

The proposal is fine except where it breaks existing code. I don't think editions should redefine syntax without a very good reason. There is a limited budget for breakage per edition. (An example of such a reason is breaking bug-prone code).

>

MySelfExplanatoryType flag = MySelfExplanatoryType.A | MySelfExplanatoryType.B MySelfExplanatoryType.C;

For that, we could add this to the language:

with MySelfExplanatoryType flag = A | B | C;

And generally, why not use the enum keyword? Let enum.X infer the enum type depending on use. Yes, enum. is 5 characters whereas . is just 1, but it’s so much clearer and breaks no code.

I get that setState(invalid) is nicer to the programmer than setState(enum.invalid), but the advantage is that there’s zero ambiguity of intent.

There could even be a new parameter storage class named with that would allow dropping enum. for constants of a particular enum type:

class Widget
{
    void setState(with State newState) { … }

    void set(StateTag _ = StateTag(), with State newState) { … }
    void set(ShapeTag _ = ShapeTag(), with Shape newShape) { … }
}

void main()
{
    Widget w = new Widget;
    w.setState(State.invalid); // okay
    w.setState(enum.invalid); // new: okay, general enum type inference
    w.setState(invalid); // new: okay, special `with` parameter

    w.set(newState: invalid); // new: okay, special `with` parameter
    w.set(newShape: square); // new: okay, special `with` parameter
}

A with parameter is allowed for enum type parameters, and advised when

    • either the name of the function makes absolutely clear what is passed,
    • or there is a mechanism in place that requires use of named arguments and the arguments’ name makes things clear, and
  1. there is probable cause that the function is called with members of the enum type.
July 09

On Monday, 8 July 2024 at 17:56:01 UTC, Quirin Schroll wrote:

>

Considering how $ is used in D, that is weird. Given that we have this.x in a class, why not module.x for “global” (i.e. module-scope) stuff?

This is a very clever idea, especially since the module keyword is not currently utilised outside the module declaration, and people don't often need the module scope operator to begin with.
On the other hand, enum is already used for a few things, and it's a bit long, making it . Not a terrible idea, but it lacks the elegant simplicity of .. And what's the point of replacing module scope op with module if we don't re-use . anyway?
All of this is still breaking syntax though, which more people than ever seem to be against now that we're about to have syntax backwards compatibility.

July 09

On Monday, 8 July 2024 at 18:17:16 UTC, Quirin Schroll wrote:

>

For that, we could add this to the language:

with MySelfExplanatoryType flag = A | B | C;

Unfortunately this only helps with bit-flag style enums. Using with for those is already some kind of solution (same as for large switch statements). This is why my examples focus on the (in my experience) everyday case of using many different enum types, usually passed to function calls, but only ever using a couple of literals per enum type, and having these scattered throughout your code without a good spot to use a with block to shorten any of them. with is a great feature, but it only solves the problem of mass repetition for one type in one place at a time. Yes, you can stack with, but when you're using 5 different types, once each, using with is like applying a bandaid to help with internal bleeding.

>

I get that setState(invalid) is nicer to the programmer than setState(enum.invalid), but the advantage is that there’s zero ambiguity of intent.

Having no prefix like that is definitely not my preference at all. Primarily I'd like setState(.invalid), but I'm open to other prefixes. If we're going for an explicit syntax that doesn't break anything existing then I vote for \, or :, or maybe # if we can reclaim it from the clutches of dmd's grammar. We also haven't examined ?, but that option relies on Walter's sumtype ? prefix not going into the language (I'm not sure where that's at right now).

>

There could even be a new parameter storage class named with that would allow dropping enum. for constants of a particular enum type:

class Widget
{
    void setState(with State newState) { … }

    void set(StateTag _ = StateTag(), with State newState) { … }
    void set(ShapeTag _ = ShapeTag(), with Shape newShape) { … }
}

void main()
{
    Widget w = new Widget;
    w.setState(State.invalid); // okay
    w.setState(enum.invalid); // new: okay, general enum type inference
    w.setState(invalid); // new: okay, special `with` parameter

    w.set(newState: invalid); // new: okay, special `with` parameter
    w.set(newShape: square); // new: okay, special `with` parameter
}

A with parameter is allowed for enum type parameters, and advised when

    • either the name of the function makes absolutely clear what is passed,
    • or there is a mechanism in place that requires use of named arguments and the arguments’ name makes things clear, and
  1. there is probable cause that the function is called with members of the enum type.

This just a bit too much. Less is more when it comes to type inference, and a simple shortcut should become a whole system where the caller has to keep track of whether the callee allows them to use a shortcut or not, while still having the ambiguity of not writing any kind of 'inferred type' prefix.
With a short prefix there can no ambiguity as to whether type inference is being used or not, while still keeping code succinct.

July 09

On Monday, 8 July 2024 at 10:41:39 UTC, Nick Treleaven wrote:

>

Vladimir's idea is for an identifier to have its own type. When omitting the struct type, there is no identifier. So that idea doesn't have a bearing on being able to do that.

MyStruct x;
x = _(args); // type identifier not present

I see what you mean, but _ is actually an identifier. ;) I know a lot of us would like to deprecate it favour of pattern matching discards/etc., but it would still be a considerable syntax break.
To solve the issue you mentioned about there being no identifier, instead of having a type for an identifier, we make another similar type that stores just a list of parameters.

>

BTW it would be nice to be able to omit the class type in a NewExpression too:

MyClass obj;
obj = new _(args);

Absolutely, that's a great idea! Now, this presents an interesting question:
Can new+type inference only be used for classes, or can new MyStruct(args) also be shortened to new _(args)? Personally I think allowing structs makes sense.
Class type inference would certainly grant a bit less benefit than for other aggregates due to polymorphism, but as long it's doable I'm down for it. I guess I should mention that I think union literals should get type inference too before someone brings those up. One really cool way of inferring their type would be via named parameters.

July 09
On 09/07/2024 3:51 PM, IchorDev wrote:
> On Monday, 8 July 2024 at 10:41:39 UTC, Nick Treleaven wrote:
> 
>     Vladimir's idea is for an identifier to have its own type. When
>     omitting the struct type, there is no identifier. So that idea
>     doesn't have a bearing on being able to do that.
> 
>     |MyStruct x; x = _(args); // type identifier not present |
> 
> I see what you mean, but |_| is actually an identifier. ;) I know a lot of us would like to deprecate it favour of pattern matching discards/etc., but it would still be a considerable syntax break. To solve the issue you mentioned about there being no identifier, instead of having a type for an identifier, we make another similar type that stores just a list of parameters.

It is used quite heavily to mean that the variable isn't used for say foreach statements.

However we will not be diverging from C's identifiers. We are in the process of bumping the version from C99 to C23.

I can say this on behalf of Walter, due to that bump being something I had to fight for.
July 09

On Tuesday, 9 July 2024 at 03:57:47 UTC, Richard (Rikki) Andrew Cattermole wrote:

>

It is used quite heavily to mean that the variable isn't used for say foreach statements.

‘Used to mean’—I use it for that too, but it’s a convention not a language feature. (Unless it’s undocumented?)

>

We will not be diverging from C's identifiers.

Fortunately there are plenty of good prefixes that don’t require diverging from C’s identifiers.

>

We are in the process of bumping the version from C99 to C23.
I can say this on behalf of Walter, due to that bump being something I had to fight for.

And thank you for doing that!