Re: bind/shroud bug

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

Putting together a test for the routine_id problem, I discovered that I've
ecountered a problem with bind/shroud, not routine_id.

Here's an example that demonstrates the bug; it uses 3 files:

--- file: TEST1.E ---
   procedure test()
   end procedure

   global constant test1 = routine_id("test")

--- file: TEST2.E ---
   procedure test()
   end procedure

   global constant test1 = routine_id("test")

--- file: TEST.EX --
   include test1.e
   include test2.e

   ? test1
   ? test2

--- end of files ---

If you run the interpreted version of the code, you get the results:

   0
   1

This indicates that each constant resolved to a *different* function. I
maintain that a return value of 0 is confusing (well, *I* keep tripping up
on it), but that's a different kettle of fish. Now, if you bind the file,
with -clear_routines:

   c:\euphoria> bind -clear_routines test.ex
   creating test.exe ...
   local symbol test conflicts with an earlier symbol
   it will be renamed as C.

executing the program gets the result:

   0
   0

The first problem is that since bind renamed the second procedure to 'C'
(insert obligatory C programming joke here), it's effectively invisible to
routine_id.

The second problem is that the first routine is local to a different include
file. Scoping rules say that the second routine_id shouldn't see it at all.

I've tested this with a shrouded file, and gotten the same results.

Now, I *know* I can solve the problem by renaming the routines. But that
sidesteps the real issue here: bound/shrouded code BEHAVES DIFFERENTLY. This
is a Bad Thing, and people are not going to be able to convince me
otherwise.

Why do the errors happen? My guess is that it has to do with how bind/shroud
merge multiple files into a single file. It would appear that they try to
convert the files into something like this:

--- bound/shrouded file without clear_routines ---

   procedure A()
   end procedure

   global constant B = routine_id("test")

   procedure C()
   end procedure

   global constant D = routine_id("test")

   ? B
   ? D

--- end bound/shrouded file without clear_routines ---

The reason that bind/shroud renames your routines is not just to make your
code more compact or secure. Since all the routines are placed into the same
module, there are no local module items any more. Renaming avoids name
collisions.

As is obvious from the above example, routine_id will fail, because there
are no longer any routines called "test" - they are now named "A" and "B".
Euphoria knows this, and issues a warning that you need to use the
-clear_routines option if it sees routine_id in your code.

If -clear_routines simply left the routine names alone, it would create
this:

--- shrouded file with -clear_routine ---

   procedure test()
   end procedure

   global constant test1 = routine_id("test")

   procedure test()
   end procedure

   global constant test2 = routine_id("test")

   ? test1
   ? test2

--- end shrouded file with -clear_routine ---

This obviously won't work, because there are two routines with the name
'test'. Robert's solution was clever, but (sorry to say this) wrong: if
there is a name conflict, only allow the first routine to keep it's original
name.

So the resulting file (apparently) looks like this:

--- shrouded file with -clear_routine ---

   procedure test()
   end procedure

   global constant test1 = routine_id("test")

   procedure C()
   end procedure

   global constant test2 = routine_id("test")

   ? test1
   ? test2

--- end shrouded file with -clear_routine ---

Note that the first version of 'test' keeps the name, but the second is
renamed to 'C'.  (The naming of the procedure to 'C' instead of 'A' hints at
how bind/shround was modified, but that's another tangent.)

Why would Robert use a solution like this? My guess is that it meant he
would only have to rewrite the bind/shroud routine, instead of altering
Euphoria itself. The inclusion of routine_id into Euphoria was causing major
hassles, and this was a quick fix.

But it's a bad fix, because it causes code to behave differently once it's
been bound/shrouded. As Robert says in the C.DOC file about why Euphoria is
better than C:

   because you hate it when your program
   starts working just because you added a
   debug print statement or compiled with
   the debug option

I say the same thing about bind/shroud.

So here's the conflict: bind/shroud needs to rename things (so they happily
coexist in a single namespace), while routine_id needs the actual name.

I suggest (in my infinite naivite) that a good solution should be fairly
easy to obtain - just add two new tokens to bind/shroud:

   <<start of include>>
   <<end of include>>

These would serve to simulate what include does - tell the interpreter that
a new file is being loaded, or exited.

Here's what the bound/shrouded file would look like (with -clear_routines):

-- suggested solution --

   <<start of include>>

   procedure test()
   end procedure

   global constant test1 = routine_id("test")

   <<end of include>>
   <<start of include>>

   procedure test()
   end procedure

   global constant test1 = routine_id("test")
   <<end of include>>

   ? test1
   ? test2

-- end suggested solution --

Adding these tokens would ensure that bound/shrouded files are built
internally the same as plain interpreted programs. I think that this is a
good solution because it:

   - makes code bound/shrouded code run correctly
   - should be easy to implement
   - doesn't add any new features
   - doesn't break any old features
   - is backward compatible
   - is simple

Comments?

-- David Cuny

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

Search



Quick Links

User menu

Not signed in.

Misc Menu