July 22, 2021

On Tuesday, 20 July 2021 at 15:50:49 UTC, russhy wrote:

>

Hello

I all the time wondered why we always have to be so much verbose with enum, when it's not casting to primitives, it is about repeating their long type name, constantly, all the time

After trying some other languages over the past few years, i discovered in zig you can just ommit the enum type name and just use enums this way: .MY_VALUE

I don't know if that's something that could be supported with D, i am not a compiler dude, so i don't have the answer

Adam on discord mentioned using with(ENUM_TYPE) or just an alias, but i think we go ahead and make it simple

I had prepared a DIP [1], not ready at all, but i wanted to initiate some discussion about that feature

So what do you think? yay? nay? why not?

[1] https://github.com/RUSshy/DIPs/blob/patch-2/DIPs/DIP1xxx.md

Terrible, just terrible.

July 22, 2021

On Thursday, 22 July 2021 at 03:28:44 UTC, Paul Backus wrote:

>
enum E : string { x = "y", y = "x" }

E e = "y"; // what happens here?

The VRP mechanics do not currently let that compile, so nothing will break. it would be equal to E e = E.y; E e = cast(E)"y" on the other hand would still be E e = E.x, as it's now.

Now, I admit that difference between implicit and explicit cast is confusing and a weakness. Maybe the syntax should be E e = ".y" instead to avoid the difference in behaviour between implicit and explicit cast.

July 22, 2021

On Thursday, 22 July 2021 at 14:05:53 UTC, Dukc wrote:

>

On Thursday, 22 July 2021 at 03:28:44 UTC, Paul Backus wrote:

>
enum E : string { x = "y", y = "x" }

E e = "y"; // what happens here?

The VRP mechanics do not currently let that compile, so nothing will break. it would be equal to E e = E.y; E e = cast(E)"y" on the other hand would still be E e = E.x, as it's now.

Now, I admit that difference between implicit and explicit cast is confusing and a weakness. Maybe the syntax should be E e = ".y" instead to avoid the difference in behaviour between implicit and explicit cast.

Ok, now imagine you're new to D and don't know about this feature. What are you going to think E e = ".y" does?

Using string-literal syntax for things that aren't actually string literals is just asking for confusion.

July 22, 2021

On 7/21/21 7:59 PM, Walter Bright wrote:

>

On 7/21/2021 2:16 PM, Steven Schveighoffer wrote:

>

No, mixin something; thenCallFunction(...); isn't even close to the same.

I don't know what it is you're asking for, then.

I'm not asking for anything. What I'm saying is the feature in Swift (called "dot syntax") that allows one to use .enumMember wherever a specific enum is required, is not the same as creating symbol aliases for all the enum members in your namespace (or in module namespace). The Swift feature is contextual based on the expression type, and doesn't require any extra machinery around it. This means that you don't have weird ambiguities when you have multiple enums as parameters, or names that are local that might override the names. e.g.:

enum A
{
   one,
   two,
   three
}

enum B
{
   one,
   two,
   three
}

void foo(A a, B b) {... }

// how to call foo without having to specify `A.one` or `B.one`?

In Swift, .symbol is specifically for type properties, and fit perfectly for enums (and other things, see here). It does not have the meaning that D has, so it can get away with this.

I don't expect D to implement such a thing, and yes, you can do mixin hacks or with statements (though there are drawbacks to both). Just saying .member instead of FullEnumType.member whenever a FullEnumType is required is a nice feature of Swift, and I would like to see something like it in D, but I can live without it. BUT if it were to be implemented, obviously .symbol doesn't work. That's why I proposed a shortcut to mean "property of the required type" such as #.symbol.

-Steve

July 22, 2021

On Wednesday, 21 July 2021 at 15:13:36 UTC, Petar Kirov [ZombineDev] wrote:

>

OTOH, allowing target-typed literals in one place (variable init / assignment) and not in other (function calls) could be regarded as a pointless and artificial design limitation (similar to how struct literals are allowed only for variable initialization).
That could be the reason why C#'s language team decided to allow target-typed new expressions in both contexts with C# 9:

IMO D's target-typed literals (also called "polysemous literals") are also a misfeature. They lead to weird, unintuitive situations where seemingly-equivalent code has different behavior; for example:

import std.stdio;

void fun(double[] arr) { writeln("double"); }
void fun(T)(T[] arr) { writeln(T.stringof); }

void main()
{
    fun([1, 2, 3]);
    auto arr = [1, 2, 3];
    fun(arr);
}

A language with fully-context-aware type inference would infer both arrays as double[]. A language with fully-context-independent type inference would infer both as int[].

In D, however, we get the worst of both worlds: type inference is mostly context-independent (so we have to add type annotations even in cases that are unambiguous), but there are a few special cases where context is taken into account (so we have to be mindful of context when refactoring, since a change in context could change the inferred type of an expression).

July 22, 2021

On Thursday, 22 July 2021 at 16:41:30 UTC, Paul Backus wrote:

>

IMO D's target-typed literals (also called "polysemous literals") are also a misfeature. They lead to weird, unintuitive situations where seemingly-equivalent code has different behavior; for example:

import std.stdio;

void fun(double[] arr) { writeln("double"); }
void fun(T)(T[] arr) { writeln(T.stringof); }

void main()
{
    fun([1, 2, 3]);
    auto arr = [1, 2, 3];
    fun(arr);
}

A language with fully-context-aware type inference would infer both arrays as double[]. A language with fully-context-independent type inference would infer both as int[].

In D, however, we get the worst of both worlds: type inference is mostly context-independent (so we have to add type annotations even in cases that are unambiguous), but there are a few special cases where context is taken into account (so we have to be mindful of context when refactoring, since a change in context could change the inferred type of an expression).

It’s not so bad IMO. Type inference in D isn’t far from just “forward, one step at a time”, which is easy to understand but still very powerful.

July 22, 2021
On 7/22/2021 9:16 AM, Steven Schveighoffer wrote:
> ```d
> enum A
> {
>     one,
>     two,
>     three
> }
> 
> enum B
> {
>     one,
>     two,
>     three
> }
> 
> void foo(A a, B b) {... }
> 
> // how to call foo without having to specify `A.one` or `B.one`?
> ```
> 
> In Swift, `.symbol` is specifically for type properties, and fit perfectly for enums (and other things, see [here](https://www.swiftbysundell.com/tips/using-dot-syntax-for-static-properties-and-initializers/)). 


How does that interact with function overloading?

I looked at the Swift reference manual https://docs.swift.org/swift-book/ReferenceManual/Expressions.html and couldn't find answers there.

Seems to me there'd be a combinatorial explosion as the resolver will have to re-run the match for all different resolutions for `.identifier`. Even if the compiler does try them all and find a best match, for the user reading the code I doubt it would be straightforward to figure out manually which is the right match. It's already hard enough.

With the alias mixin proposed, the answer is simple. Two different enums in the same scope with the same member names will cause a compile time error.
July 22, 2021
On 7/22/2021 3:03 AM, rikki cattermole wrote:
> 
> On 22/07/2021 8:37 PM, Walter Bright wrote:
>> On 7/21/2021 11:28 PM, rikki cattermole wrote:
>>> If you can't describe it using words, use code instead.
>>
>> I tried everything, including that. I really cannot explain it. It was a very frustrating experience.
> 
> Oh hmm. I just went looking for it, the only files regarding semantic analysis I thought it could be in yup... 700 LOC method. Found that rather quickly.
> 
> That really isn't a good sign I must admit!

The symbol lookup used to be very simple and completely consistent in D. It got a *lot* more complicated as a result of my inability to explain how it worked. It does two passes now, and is very inconsistent.
July 22, 2021

On Thursday, 22 July 2021 at 17:28:02 UTC, Walter Bright wrote:

>

On 7/22/2021 3:03 AM, rikki cattermole wrote:

>

On 22/07/2021 8:37 PM, Walter Bright wrote:

>

On 7/21/2021 11:28 PM, rikki cattermole wrote:

>

If you can't describe it using words, use code instead.

I tried everything, including that. I really cannot explain it. It was a very frustrating experience.

Oh hmm. I just went looking for it, the only files regarding semantic analysis I thought it could be in yup... 700 LOC method. Found that rather quickly.

That really isn't a good sign I must admit!

The symbol lookup used to be very simple and completely consistent in D. It got a lot more complicated as a result of my inability to explain how it worked. It does two passes now, and is very inconsistent.

You mean this isn't true anymore?
https://dlang.org/spec/module.html#name_lookup

July 22, 2021
On 7/22/2021 1:37 AM, claptrap wrote:
> Sometimes i think the main problem with D is all these weird corner cases pop up and people dont say oh look we need to fix this, nail it down, make it consistent, they say or look cool a new feature!

Programming languages aren't completely consistent because:

1. people don't want them to be
2. what the software must interact with isn't consistent
3. the CPU is not consistent

This whole thread is about adding an inconsistent feature.