Namespace (take 2)

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

Hi All,

There have been lots of great suggestions and discussion on the namespace
issue. Its changed some of my thinking about the problems it is trying to
solve and the potential solutions. I don't think I've got a definitive
solution yet in my head but here is my current thinking.

** Namespaces are optional. The default is "global".
   Just so existing code will still parse okay.
    e.g..
          include graphics.e
          x = setcolor(RED)
   is identical to ...
          x = global:setcolor(global:RED)

** Only "global" symbols will be in named namespaces.
    The scope of non-global symbols is already well defined and acceptable.

** Control of the namespace ID must be with the code doing the referencing.
   The alternative means that inadvertent clashes could still occur. For
example
   if RDS creates a namespace "rds" and places all its routines in there,
then I
   come along and create a function with the same name as an RDS one and
   just happen to put mine into "rds" too, a name clash will occur.

     e.g..
        -- Syntax that forces a namespace for each include file --
        include graphics.e as rds
        include get.e as rds

    or even
       -- Syntax that bunches multiple include files into a namespace --
       namespace rds
       include graphics.e
       include get.e
       end namespace

I'd actually like both these syntaxes to be availble.

** The namespace ID must be independent of the include file name.
    File names just do not make good namespace IDs. There are also
    characters allowed in file names that are not allowed in Euphoria
    names.  
     e.g.
          include file.abc.e  -- Allowed as a file name, but not as a symbol
name.

     e.g..
        include graphics.e as rds  -- and not default to "graphics"

** Any symbol can be prefixed with a namespace reference.
   I prefer a colon character as the delimiter but this is not so important.
    e.g..
         x = rds:setcolor(rds:RED)

   If that symbol does not exist in the named namespace an error "undefined
symbol" occurs.

** If the namespace id in a prefix or a namespace list is not explicitly
defined by the current file, an error occurs "unknown namespace"
   This is another way of saying that defined namespaces are scoped to the
file they are defined in.

       -- fileA.e ----
       include graphics.e as rds

      -- fileB.e ---
      include fileA.e
      x = rds:setcolor(rds:RED)  -- Error: 'rds' not defined in fileB.e

      using rds  --Error: 'rds' not defined.
          x = setcolor(RED)
      end using

but this IS okay...

      -- fileB.e ---
      include fileA.e
      include graphics.e as rds
      x = rds:setcolor(rds:RED)

      using rds
          x = setcolor(RED)
      end using
    
** A global symbol can only be defined once in the same file.
   This is current semantics and no need to change.

** A symbol can only exist in a namespace once.
   Otherwise, how would Euphoria know which symbol you are referring to?

** Attempting to put a symbol into a namespace and that symbol already
exists there,
   is not an error if both symbols come from the same file.

   This is consistent with current Euphoria.

   e.g..
      -- Current Euphoria --
       include graphics.e
       include graphics.e  -- This is not an error, it is ignored.

      -- Proposed Euphoria --
       include graphics.e as rds
       include graphics.e as rds -- This is not an error, it is ignored.

** A reference to the same symbol can exist in multiple namespaces.
   This situation is bound to happen sometimes and I can't think of a good
reason why it should be an error.
   Also, with my "insert" idea described further down, this is more likely
to happen.

  e.g..
     include graphics.e as rds
     include graphics.e as dos
     include graphics.e as std

     x = std:setcolor(std:RED)
     y = dos:setcolor(dos:RED)  -- Exactly the same objects referred to.
    
** The coder can specify a namespace list and its scope. The default
namespace list is "global".
   This can save a lot of coding and extra reading. It also makes "fixing"
up pre-2.3 code easier.

    e.g..
 include graphics.e as rds
 include win32lib.ew as w32
 include colornames.e as clr

 using rds,w32 
    x = setcolor(BrightRed) -- setcolor from "rds" even though "w32" might
have one,
                            -- BrightRed from "w32" even though "clr" might
have one.
    y = setcolor(Blue)
    z = setcolor(White)
 end using

The alternative, and also legal syntax would be...

 include graphics.e as rds
 include win32lib.ew as w32
 include colornames.e as clr

 x = rds:setcolor(w32:BrightRed)
 y = rds:setcolor(w32:Blue)
 z = rds:setcolor(w32:White)

** Namespace lists can be nested.

   e.g..
        include trial\graphics.e as rds
        include graphics.e
        include win32lib.ew as w32

        using rds
             x = setcolor(RED)  -- from "trial\graphics.e"
             using w32
                    y = setcolor(BrightRed) -- from "win32lib.ew"
                    z = global:setcolor(global:RED) -- from "graphics.e"
             end using
             setText(myfld1, x)
             setText(myfld2, y)
             setText(myfld3, z)
       end using

** The search path for symbol resolution should be...
     1) The namespace prefix, if present, on a symbol.
     2) The current function or procedure
     3) The current file
     4) The namespace list currently in scope. (Remember that global is the
default)

Now even with the stuff covered above there are at least three real
situations that will still be problematic, unreasonably so in my opinion.

=============
Situation #1
=============
How can I have a number of include files share access to some symbols that I
do not want to share with other files? David Cuny highlighted this problem.
It occurs when breaking up a larger include file (e.g.. win32lib.ew) into a
number of smaller files. While the (local) routines where all in same file
they could refer to each other as "private" routines, specifically not
available to coders using the library. However, once you split them into
separate files, the local routines are now hidden. To make them available to
each other, via a global specifier, also exposes them to other coders. C++
kind of got around this situation by inventing "friend" classes. This is
just a complex kludge that is not really helping. A simpler solution is the
have Euphoria pretend that these files are still in the same master file,
then all the normal semantics apply. My idea is to introduce a "insert"
command to be used instead on "include". Any file "inserted" would be
treated by the Euphoria interpreter as if its contents where actually at the
line of insertion.

e.g..
     --- fileA.ew --
        x = funcA()

     --- win32lib.ew --
     function funcA()
         return ...
     end function

     insert fileA.ew

this would still keep "funcA" private to these files.


==================
Situation #2
==================

    -- fileA.e --
    global constant WM_NOTIFY = 15

    -- fileB.e --
    global constant WM_NOTIFY = 15

    -- fileC.ex --
    include fileA.e
    include fileB.e

This currently causes a problem of duplicate definitions. The new rules
outlined above don't help either. But why should it be a problem? This type
of situation comes up when we have to define constants that come from other
environments. In my case, there are thousands of symbols defined by
Microsoft for use with Windows programming. It makes reasonable sense that
everybody should stick to the same symbol names defined by Microsoft rather
than coming up with their own variants. But that is where Euphoria has
problems. If Bill writes an include file that needs some Windows constants
and Jill writes another such include file all is well. But when Derek tries
to include those files written by Bill and Jill into my code, Euphoria barfs
if it just happens that the same Windows constants were defined (as global)
in two or more of these files.

I'd like Euphoria's behavior to change such that when a duplicate constant
(local or global) is defined, it is only an error if that has a different
value. Thus ...

    -- fileA.e --
    global constant WM_NOTIFY = 15

    -- fileB.e --
    global constant WM_NOTIFY = 14

    -- fileC.ex --
    include fileA.e
    include fileB.e

would cause a problem because the same constant is being given different
values.

And while we're at it, how about allowing constants to be defined inside a
function/procedure. It would increase Euphoria's orthoganiality!

   e.g..

     procedure procA(sequence CustomerRecord)
       sequence lAddress
       constant Street = 1 , PostalCode = 2
  
       if length(CustomerRecord) = 7 then
            lAddress = CustomerRecord[3 .. 4]
       else
            lAddress = {CustomerRecord[5], CustomerRecord[3]}
       end if

       if length(lAddress[Street]) = 0 then ....
     end procedure

===================
Situation #3
===================

Another way of avoiding global name clashes is to only include the "correct"
file.
This might be arranged like ...

   object GuiSys

   GuiSys = lower(getenv("GUISYSTEM"))
   if equal(GuiSys, "motif") then
      include motif\gui.e
   elsif equal(GuiSys, "os2") then
      include os2\gui.e
   elsif equal(GuiSys, "playstation2") then
      include playstation\2\gui.e
   elsif equal(GuiSys, "windows") then
      include windows\gui.e
   elsif equal(GuiSys, "amiga") then
      include amiga\gui.e
   elsif equal(GuiSys, "palm") then
      include palm\gui.e
   else
      abort(0) -- No GUI system defined.
   end if
   . . .
   setText(myFld, "Hello world") -- picks up the "correct" version of
setText().

In this case, the interpreter would only "include" the file if the condition
was met and would not even look into the other files.

Another simpler example:

   if atom(getenv("DEBUGGING")) then
      include machine.e
   else
      include safe.e
   end if

And I haven't even touched on all the other neat "wishlist" items that I
have for Euphoria.

-----------
cheers,
Derek Parnell
Senior Design Engineer
Global Technology Australasia Ltd
dparnell at glotec.com.au

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




confidential information intended solely for the use of the individual or
entity to whom they are addressed. If you are not the intended recipient of
this message you are hereby notified that any use, dissemination,
distribution or reproduction of this message is prohibited. If you have
received this message in error please notify the sender immediately. Any
views expressed in this message are those of the individual sender and may
not necessarily reflect the views of Global Technology Australasia Limited.

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

Search



Quick Links

User menu

Not signed in.

Misc Menu