Re: symbol resolution (was:EuCOM : Attn Matt : String Return Value)

new topic     » goto parent     » topic index » view thread      » older message » newer message

Pete Lomax wrote:
> 
> Matt Lewis wrote:
> > 
> > I wonder if we're talking past each other?  I'll adopt your example from
> > above:
> > 
> > }}}
<eucode>
> > app.ex
> >   include main.e main.e
> >     global Z
> >     include libAmisc.e
> >       if Z then
> >     include libA.e
> >       global Z
> >       include libAmisc.e
> >          if Z then
> >   ? Z -- back in app.ex
> > </eucode>
{{{

> > 
> > I was talking about how to resolve Z.  I'd say that an unqualified Z in 
> > this instance should get you main:Z.
> 
> No, I'm really not getting this. Blindly assuming it is always the first Z
> just
> seems completely wrong to me. If I was struggling with some function in libA,
> and tried setting or printing Z, I'd be miffed enough when I finally found out
> about the Z in main.e. What if (an extra level of nesting and) I then did an
> "include libA as A" to force the issue, and it crapped on some previously
> working
> use of unqualified Z later on because of this rule? Just force the namespace
> qualifier. It is not as if this case happens very often.

Well, in the example I gave, I think the reference to Z in libAmisc.e
can *only* refer to main.e.  Consider that at the time it is parsed 
(when main.e includes it) there is only one Z in existence.  The interpreter
cannot possibly know about libA:Z, and has only one reason to doubt that
it meant main:Z, which is that libAmisc.e does not include any file
that has a Z declared.

This is perfectly legal behavior, even if it is dangerous for exactly
the reasons above.  The proper thing for the author of libA to do would
have been to put an "include libA.e" at the top of libAmisc.e, since 
it depends on having that file around.  That way, if someone decides to
include libAmisc.e, it will still behave as it is supposed to.  If
libA.e is included first (or only) then the include statement in libAmisc.e
only serves to inform the interpreter about where it expects to get
symbols.

Before I get into the issue of masking (which I believe is subtly 
different from this eaxmple) I think it's important to  reiterate the
purpose of this family of enhancements:

* Make it possible and easier to use multiple third party libraries.
* Avoid certain namespace conflicts where there is a reasonable or
  obvious way to resolve the conflict.
* Reduce or eliminate the need to have to edit third party libraries to
  resolve namespace conflicts.

Obviously, it will be possible for someone to write a library such that 
it may conflict with other code (possibly another poorly written library).
There's only so much that we can do inside the interpreter.

Now, on to the masking issue:
-- app.ex
include lib.e as lib
  global Z
  include sublib.e
    global Z
include sublib.e as sublib
? Z         -- #1 compile error
? lib:Z     -- #2 lib:Z
? sublib:Z  -- #3 sublib:Z

I'm not sure why someone would write code like this, but I'm sure that it's
either been done already or will be done.  Under 3.1, we could access
either one by using a namespace in app.ex.  I've proposed extending the
namespace for lib.e to include sublib.e.  I think this is useful, because
it avoids requiring library users to understand the structure of, say,
win32lib, and simply use one namespace for all of win32lib.

However, in this case, we have to decide what to do when we encounter
something like lib.e and sublib.e.  We can use a namespace identifier to
access sublib:Z, but if we try to use lib:Z, there are now two 
possibilities.  After reading your priorities, and (IIRC) on of CChris' 
arguments, I believe that it's reasonable to assume that using
lib:Z from app.ex means that, in fact, you want lib:Z and not sublib:Z.

But what if there is no namespace identifier?  In this case, it's probably
correct to throw a compile error.  

Back to using a namespace.  I'm also thinking that we should only allow
the "top-level" symbol to mask other symbols.  IOW, I wouldn't use a
full priority table like you did, but only divide the symbols into two
groups, the symbols in the explicitly namespaced file, and the symbols
in all of its includes:
--app.ex
include lib.e as lib
  include sub1.e
    global Z
    include sub2.e
      global Z
include sub1.e as sub1
include sub2.e as sub2
? Z      -- #1 compile error
? lib:Z  -- #2 compile error
? sub1:Z -- #3 sub1:Z
? sub2:Z -- #4 sub2:Z

Consider that if there were no mask, it would be impossible to reference
sub1:Z.

I believe that this behavior follows these rules:

  1: Unambiguity and Least Surprise
  2: Zero impact on legacy code
  3: Minimal performance impact

In fact, now that I think about it, the masking behavior described is 
required to achieve #2.

Matt

new topic     » goto parent     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu