View mode: basic / threaded / horizontal-split · Log in · Help
September 29, 2012
Re: I have a feature request: "Named enum scope inference"
On Saturday, 29 September 2012 at 07:04:19 UTC, kenji hara wrote:
> After a while, you may add a global variable in module scope.
>
>   enum E { foo ,bar }
>   int foo = 10;
>   void test(E e) {}
>   void main() {
>     test(foo);  // foo is defined, and look up module scope foo.
>     // Then, now the code is broken implicitly!
>   }
>
> This is a hijacking of local scope, and it is awful.

That code doesn't compile anyway, because the global foo is an 
int. But you're right, my suggestion doesn't work. Or, there's no 
way to implement it without breaking existing code. Here's the 
reason again for completeness sake:

enum E { foo, bar };

void test(E e) {}

int intValue = -1;

void main()
{
    int intValue = 42; // Hides the global intValue.

    E foo = E.bar; // This is fine. A local variable foo hides
                   // E.foo from 'implicit global visibility'.
                   // It's effectively same as hiding a global.

    test(foo); // Calls test(E.bar)
}

-----------------------------------------------------

enum E { foo, bar };

void test(E e) {}

void main()
{
    test(foo); // Calls test(E.bar)
}

E foo = E.bar; // This is very bad. A global variable foo hides
               // E.foo from being implicitly globally visible
               // (where applicaple)


On Saturday, 29 September 2012 at 07:04:19 UTC, kenji hara wrote:
>
> It seems to me the root problem is that using a raw-identifier 
> for the start of the inference.
> If there is a symbol literal, the problem may be solved.
>
>   test('bar);  // bar is a symbol, so it does not refer any 
> normal declarations

That would work. I'd be fine with this kind of wild-card enum 
literal.
September 29, 2012
Re: I have a feature request: "Named enum scope inference"
But, if we were allowed to make a breaking change, then this is 
how I think it should work:

// in a module scope...

enum E { foo, bar };

-------------------------------------------------------------

// These cause a compile error "foo is ambiguous":
1) E foo = E.bar;
2) E foo = E.foo;
3) enum foo = E.bar;
4) immutable foo = E.bar;
5) immutable foo = initFoo(); // if we can't CTFE initFoo()

// These are fine:
1) enum foo = E.foo;
2) immutable foo = E.foo;
3) int foo = 42; // int isn't implicitly convertible to E
4) E Foo = E.bar;

-------------------------------------------------------------

struct Convertible
{
    E _value;

    alias _value this;
}

Convertible foo; // Compile error: foo is ambiguous

-------------------------------------------------------------

struct MyStruct(T)
{
    T foo = 123; // Fine, hides E.foo inside MyStruct scope

    void fun()
    {
        T foo = 42 // Fine, hides both MyStruct.foo and
                   // E.foo inside this function scope
    }
}

Here's the logic of it:
-----------------------
An enumeration of type E should be visible (like it was a module 
scope variable) if, and only if, it occurs in one of these 
"hot-spots" where a value of type E is expected (e.g. it could be 
in a template parameter list, function argument list, or in a 
case expression of a switch).

Inside these "hot-spots" the enumeration fights over visibility 
against variables. It loses that fight against function local and 
class/struct local variables which have the same name (and 
whatever type). But it wins the battle over visibility against 
module scope variables which have the same name but are not 
implicitly convertible to type E. Against global variables which 
are of type E or are implicitly convertible to type E, the battle 
over visibility ends in a tie, and that's a compile-time 
ambiguity error.
September 29, 2012
Re: I have a feature request: "Named enum scope inference"
On 9/29/12 2:44 PM, Tommi wrote:
> But, if we were allowed to make a breaking change

I stopped reading here :o).

Andrei
September 29, 2012
Re: I have a feature request: "Named enum scope inference"
Scratch my previous post. It had a weird rule where the types of 
identifiers had a say in whether or not there's ambiguity in the 
name lookup. That's just silly. It should always be an ambiguity 
error if the names are identical.

This new rule is easier to conceptualize too. Basically you just 
think that there are these "hot-spots" (they're red, I think) in 
your code wherever named enum values are expected. Inside each 
"hot-spot", the name lookup is allowed to think that all the 
enumerations (the enumerated identifiers) of that particular 
named enum type are in module scope. And that's it.

So, again... if we were allowed to make a breaking change, this 
is how I think it should work:

// in a module scope...

enum Char { a, b, c, d, e }

Char a = Char.c; // OK
auto b = a;      // OK: .b == Char.c
Char c = Char.a; // OK: .c == Char.a

Char d = a; // ERROR: 'a' could be either 'Char.a' or '.a'
            // because now 'a' is in a "hot-spot", where a
            // value convertible to type Char is expected,
            // and thus all Char enumerations can be seen
            // as if they were in module scope

int e = 42; // OK

void test(Char ch) {}

struct MyStruct
{
    int a = 1; // OK: hides '.a'

    void fun()
    {
        Char a = Char.e; // OK: hides 'MyStruct.a' and '.a'

        test(a); // OK: calls 'test(Char.e)' although the test
                 // argument 'a' is now in a "hot-spot" where
                 // all the enumerations of Char (a, b, c, d, e)
                 // are considered to be in module scope. But
                 // the function local 'a' hides anything that
                 // might be in module scope, so the name lookup
                 // doesn't even bother looking at module scope.

        test(e); // ERROR: 'e' could be either 'Char.e' or '.e'
                 // because now the name lookup has to look at
                 // the module scope, where we have also Char.e
                 // visible due to the fact that argument 'e'
                 // is in a "hot-spot". It doesn't matter from
                 // our name-lookup's point of view that test
                 // is not callable with an int value.
    }
}
September 29, 2012
Re: I have a feature request: "Named enum scope inference"
Although it's not very obvious what is a "hot-spot" and what is 
not.

enum Char { a, b, c, d }

Char a = c; // OK: 'c' is in a "hot-spot"

Char b = c + 1; // ERROR: 'c' is undefined, because it's not in
                // a "hot-spot" and therefore Char enumerations
                // aren't visible. The expression c + 1 is
                // expected to return Char but there's no reason
                // to expect the arguments of that expression to
                // be of type Char. (Another error would be that
                // c + 1 doesn't even return Char, but we never
                // get that far because the name lookup fails)

int c = 42;

void test(Char ch) {}
void test(int val) {}

void main()
{
    test(c); // OK: calls test(.c) because arg 'c' is not in a
             // "hot-spot". Function 'test' isn't expecting a
             // Char variable as an argument, it's expecting a
             // type chosen from set of types (among which Char
             // just so happens to be). But, if you remove the
             // test(int) specialization, this function call
             // fails, and the one on the next line succeeds.

    test(d); // ERROR: 'd' is undefined, because it's not in a
             // "hot-spot" for the reason specified above, and
             // therefore enumerations of Char are not brought
             // into the module scope.
}

It is quite a mess. I think I'm ready to admit that this is not a 
feature we'd like to have in this language (probably not in any 
language for that matter).
September 29, 2012
Re: I have a feature request: "Named enum scope inference"
On Saturday, 29 September 2012 at 02:57:42 UTC, David Piepgrass 
wrote:
>> I have a feature request: "Named enum scope inference"
>>
>> The idea is, that whenever a named enum value is expected, you 
>> don't need to explicitly specify the scope of the enum value. 
>> This would reduce redundancy in typing, just like automatic 
>> type inference does.
>>
>> Examples:
>> ---------
>>
>> enum MyDirection { forward, reverse }
>> struct MyIterator(MyDirection dir)
>> {
>>    ...
>> }
>>
>> int forward = 42; // Doesn't interfere with the next line...
>> auto itr = MyIterator!forward(); // Infers MyDirection.forward
>
> I like the spirit of this feature, but as Alex pointed out, 
> ambiguity is possible (which could theoretically cause errors 
> in existing code) and while I'm not familiar with how the 
> compiler is implemented, my spidey-sense thinks that what 
> you're asking for could be tricky to implement (in a language 
> that already has a very large amount of rules and features.) 
> Plus, I don't like the fact that when you see something like 
> "MyIterator!forward" by itself in code, there is no obvious 
> clue that forward is an enum value and not a class name or a 
> variable. So there is a sort of decrease in clarity of the 
> entire language by increasing the total number of possible 
> meanings that an identifier can have.
>
> So I think this feature would need a more clear syntax, 
> something to indicate that the value is an enum value. I don't 
> currently have a really good counterproposal though....

+1
September 30, 2012
Re: I have a feature request: "Named enum scope inference"
On Saturday, 29 September 2012 at 23:49:47 UTC, Tommi wrote:
> It is quite a mess. I think I'm ready to admit that this is not 
> a feature we'd like to have in this language (probably not in 
> any language for that matter).

Using "with" should do the trick just fine for the few situations 
where there's too much redundant typing. I think adding new 
features needs to take a distant back seat to the far FAR more 
important issues in need of repair. For example, I cannot run D 
reliably from C/C++, yet that is one of the advertised features 
that compelled me to seriously consider D as a viable alternative 
to C/C++. What about dynamic linking? Nope, not yet. This is 
basic stuff!

Should anyone really care about reducing the amount of typing you 
have to do when they can barely even use the language as it 
currently stands?

There are however seemingly trivial items that probably should be 
added to D, but not as a convenience, instead to make it truely 
practical in a production environment.

Now having said the above, the last thing D should become is 
stagnant for sake of preserving backwards compatibility. D2 is 
not D1, and D3 should not have to be D2. Personally, I'm in favor 
of the idea of breaking existing code so that past mistakes can 
be repaired and significant improvements can be implemented, but 
that should mean moving on to the next major version.

--rt
October 01, 2012
Re: I have a feature request: "Named enum scope inference"
Le 29/09/2012 14:04, Bernard Helyer a écrit :
> Yeah, to respond to the larger topic, the with statement
> is more than enough here. I'm not convinced that complicating
> lookup rules further is worth it.
>

Well, they are not complicated, they are mostly undefined.
Next ›   Last »
1 2 3
Top | Discussion index | About this forum | D home