September 22, 2014
On 9/21/2014 2:33 PM, Timon Gehr wrote:
> On 09/21/2014 10:08 PM, Walter Bright wrote:
>> Parameters are not in the same scope as local variables.
>
> I know, and you will know that it makes no practical difference since identifier
> shadowing is disallowed (deprecated) within a function.

The difference does become apparent when imports are done.

Also, the parameter scope matters for things like template function constraints.

September 22, 2014
Am Sun, 21 Sep 2014 23:07:26 -0700
schrieb Walter Bright <newshound2@digitalmars.com>:

> Your misunderstanding appears to be that:
> 
>     foo(int a) { int b; }
> 
> 'a' and 'b' are in the same scope. They are NOT in the same scope.

But quite understandable that people expect them to be in the same scope, seeing as there is only one set of {}. Adding some shadowing warnings should deal with that, so that the earlier example with `text` being hijacked somehow errors out.

-- 
Marco

September 22, 2014
On 21/09/14 22:04, Walter Bright wrote:

> Lookup rules are straightforward:
>
>    scope is current scope
>    do {
>        look up name in scope
>        if name is found, done!
>        look up name in imports imported into scope
>        if name is found, done!
>        set scope to enclosing scope
>     } while scope exists
>
> I don't know what mental model people have for how lookups work, but the
> above algorithm is how it actually works.

You better write down the scope rules as well. It gets complicated with base classes, template mixins and all features available in D.

-- 
/Jacob Carlborg
September 22, 2014
On 9/21/2014 11:09 PM, deadalnix wrote:
> We should simply do a lookup for local symbol, and if that fail, imported symbols.

That's what it does now, i.e. lookup in the current scope, and if that fails, look in imports, if that fails, go to the enclosing scope.

> In that case, a should resolve as the parameter, all the time.

Parameters are in an uplevel enclosing scope.
September 22, 2014
On Monday, 22 September 2014 at 06:59:14 UTC, Walter Bright wrote:
> On 9/21/2014 11:09 PM, deadalnix wrote:
>> We should simply do a lookup for local symbol, and if that fail, imported symbols.
>
> That's what it does now, i.e. lookup in the current scope, and if that fails, look in imports, if that fails, go to the enclosing scope.
>

Can't this be made depth first ? That would seem more sensible to me, and apparently to other in this thread. After all, it seems legitimate to resolve what is under your nose than what is imported (and with lazy imports, it may even allow the compiler to process some imports).

>> In that case, a should resolve as the parameter, all the time.
>
> Parameters are in an uplevel enclosing scope.

Yes I know, there is good reason for that. But from the programmer perspective, not the implementer, that do not look right.
September 22, 2014
On 9/21/2014 11:44 PM, Marco Leise wrote:
> But quite understandable that people expect them to be in the
> same scope, seeing as there is only one set of {}.

{ } introduce a new nested scope, they do not extend an existing one.


> Adding some
> shadowing warnings should deal with that, so that the earlier
> example with `text` being hijacked somehow errors out.

Are how the current lookup rules work (for better or worse) clear to you or are they still mysterious?
September 22, 2014
On 9/21/2014 11:36 PM, Jacob Carlborg wrote:
> You better write down the scope rules as well. It gets complicated with base
> classes, template mixins and all features available in D.

Sure, I had thought they were.

BTW, template mixins work exactly like imports. See "Mixin Scope" here:
https://dlang.org/template-mixin
September 22, 2014
On 9/22/14, 12:09 AM, Walter Bright wrote:
> On 9/21/2014 11:36 PM, Jacob Carlborg wrote:
>> You better write down the scope rules as well. It gets complicated
>> with base
>> classes, template mixins and all features available in D.
>
> Sure, I had thought they were.
>
> BTW, template mixins work exactly like imports. See "Mixin Scope" here:
> https://dlang.org/template-mixin

D lookup rules are logical and relatively simple.

In the case of local imports however, there's definitely an element of surprise, and also an issue akin to hijacking. Consider:

void main(string[] args) {
   import some_module;
   ... use args ...
}

Let's assume module "some_module" does not define a name "args". All works fine.

Time goes by, some_module gets updated to also define the name "args". Now this application is recompiled and may actually compile successfully, but the semantics has changed - it doesn't use the "args" in the parameter list, but instead the symbol exported by some_module.

That's clearly something difficult to ignore. It's one of those cases in which logical and relatively simple doesn't fit the bill the same way that a pair of pants built out of simple shapes like cylinders and hemispheres won't be a good fit.

We must look into this.


Andrei

September 22, 2014
On Monday, 22 September 2014 at 08:06:11 UTC, Andrei Alexandrescu wrote:
> D lookup rules are logical and relatively simple.
>

If you look at my first post, you'll notice that the discussion so far touched only a fraction of the issue (and I forgot to mention opDispatch in there).

That being said, I'm fairly sure we can come up with something logical. The problem is right now, if put aside the surprise of the local import, that various methods of resolutions are defined independently, but not how they interact.
September 22, 2014
On 9/22/2014 12:02 AM, deadalnix wrote:
> On Monday, 22 September 2014 at 06:59:14 UTC, Walter Bright wrote:
>> On 9/21/2014 11:09 PM, deadalnix wrote:
>>> We should simply do a lookup for local symbol, and if that fail, imported
>>> symbols.
>>
>> That's what it does now, i.e. lookup in the current scope, and if that fails,
>> look in imports, if that fails, go to the enclosing scope.
>>
>
> Can't this be made depth first ? That would seem more sensible to me, and
> apparently to other in this thread. After all, it seems legitimate to resolve
> what is under your nose than what is imported (and with lazy imports, it may
> even allow the compiler to process some imports).

It is depth first. It starts at the innermost scope, which is the current scope. Somehow, we don't seem to be talking the same language :-(


>>> In that case, a should resolve as the parameter, all the time.
>>
>> Parameters are in an uplevel enclosing scope.
>
> Yes I know, there is good reason for that. But from the programmer perspective,
> not the implementer, that do not look right.

I don't know of a better rule.