July 22, 2021

On 7/22/21 1:19 PM, Walter Bright wrote:

>

On 7/22/2021 9:16 AM, Steven Schveighoffer wrote:

>
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).

How does that interact with function overloading?

Swift is known for "giving up" on expression inference, so possibly it could lead there.

But note that Swift (and objective C) have significant parameter names, which means in many cases you must name the parameters when calling. This helps with overloading quite a bit (in fact, in Objective C there was no overloading, as the parameter names were part of the function name).

Which is to say, the situation in Swift is definitely different than the situation in D. Overloads are handled differently, and expectations are significantly different.

I tried out some stuff:

import Foundation

enum Foo {
    case a
    case b
    case c
}

enum Bar {
    case a
    case b
}

func test(_ : Foo) { print("test a"); }
func test(_ : Bar) { print("test b"); }

test(.a) // error, ambiguous
test(Foo.a) // test a
test(Bar.a) // test b
test(.c) // test a

So it seems to work as one might expect. Since .c can only match the first, it's used.

>

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.

But what is "all" resolutions? A combinatorial explosion of 1 or 2 possibilities isn't bad. Remember, the symbol lookup requires a contextual type. For example:

var x = .identifier // Compiler error, no type, even if only one type in scope has a member `identifier`
var y : SomeEnum = .identifier  // OK
var z : SomeEnum
z = .identifer // OK, we infer the meaning from the type of z

I know D doesn't do this. But it's also not the same as what you are saying.

>

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.

The identifier comes from the expression target's inferred type. There are still ambiguous cases, where the compiler is going to give up. But the lookup doesn't involve the whole world either.

Before you go on arguing that D doesn't do this, and shouldn't, I know. It's not that I'm trying to convince you that it should, I'm just showing what has been requested and how it differs from the "mixin solution".

>

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.

The answer is, there is no shortcut, just type out the full enum names. With Swift you do not need to.

-Steve

July 22, 2021

On Thursday, 22 July 2021 at 14:58:12 UTC, Paul Backus wrote:

>

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?

There would be a risk that I'd think that it's the same as E e = .y. Not that likely though - I may well know that E has a member y, and I could also reason that ".y" meaning .y would make no sense since one could just write .y directly.

I think you're worried about the case where I don't know that E is an enumerated type. In that case I could mistake E being some sort of string type. On the other hand, I could not fully trust that conclusion anyway, since it could also be some custom struct or union that can be initialized that way.

>

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

To some degree yes. But perhaps it's still better than new syntax.

July 22, 2021

On Thursday, 22 July 2021 at 14:58:12 UTC, Paul Backus wrote:

>

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?

Oh, I just realized adding the dot solves nothing.

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

E e = ".y"; // *Facepalm*
July 22, 2021
On 7/22/2021 11:16 AM, Steven Schveighoffer wrote:
> But what is "all" resolutions? A combinatorial explosion of 1 or 2 possibilities isn't bad. Remember, the symbol lookup *requires* a contextual type. For example:

So it appears that Swift simply gives an error if there's more than one result for .identifier, rather than trying to find a match that fits into the context.


> ```swift
> var x = .identifier // Compiler error, no type, even if only one type in scope has a member `identifier`
> var y : SomeEnum = .identifier  // OK
> var z : SomeEnum
> z = .identifer // OK, we infer the meaning from the type of z
> ```

Are you sure that's how Swift works? Inferring the type of the rvalue from the lvalue? Problems come from that, as in:

   z = x + y + .identifier;

For the rvalue, this becomes "top down" type inference, as opposed to the usual "bottom up" type inference. D is exclusively "bottom up", as it is much simpler.

> It's not
> that I'm trying to convince you that it should, I'm just showing what has been requested and how it differs from the "mixin solution".

Thanks!
July 23, 2021

On Friday, 23 July 2021 at 01:09:31 UTC, Walter Bright wrote:

>

Are you sure that's how Swift works? Inferring the type of the rvalue from the lvalue? Problems come from that, as in:

z = x + y + .identifier;

For the rvalue, this becomes "top down" type inference, as opposed to the usual "bottom up" type inference. D is exclusively "bottom up", as it is much simpler.

It could work with bottom-up inference only. It would work the same way as null did before adding the bottom type: .identifier would be a literal of an internal compiler type, let's call it EnumLiteral!"identifier". Values of that internal compiler type would implicitly convert to any enumerated type that defines identifier.

July 23, 2021
On Friday, 23 July 2021 at 01:09:31 UTC, Walter Bright wrote:
> For the rvalue, this becomes "top down" type inference, as opposed to the usual "bottom up" type inference. D is exclusively "bottom up", as it is much simpler.

D is mostly "bottom up", but there are a few corner cases [1] where it isn't, and they can lead to some very confusing errors [2].

It would probably be too disruptive to deprecate existing instances of "top down" type inference in D, but we can at least avoid adding new ones.

[1] https://forum.dlang.org/post/mnxksewxtrwlxeaazvwe@forum.dlang.org
[2] https://forum.dlang.org/thread/xkgpheuhohbffzgdbqhb@forum.dlang.org
July 23, 2021

On Friday, 23 July 2021 at 01:09:31 UTC, Walter Bright wrote:

>

Are you sure that's how Swift works? Inferring the type of the rvalue from the lvalue? Problems come from that, as in:

z = x + y + .identifier;

For the rvalue, this becomes "top down" type inference, as opposed to the usual "bottom up" type inference. D is exclusively "bottom up", as it is much simpler.

I don't disagree. I think in your example here, it's not inferring the requested type from z, but would be from the operator overload function. There are two requirements here:

  1. The type is inferred before the property is looked up (or at least, the set of possible types). Nearly everything in Swift is inferred type.
  2. The .identifier is a self-producing property based on the contextual type. That is, it is a property on the expected/inferred type, AND it produces an instance of the type.

It helps to remember also that Swift's enums are much more configurable than D's enums -- they are actual enumerations, and allow you to define properties, operators, etc. They are basically a specialized struct (so for instance, you can identify whether math is usable on them).

-Steve

1 2 3 4 5 6 7 8
Next ›   Last »