Re: 2 Pass Binder

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

EU>JJProg at CYBERBURY.NET wrote:

EU>>EU>   routine_name = commands[choice]
EU>>
EU>>EU>   ? call_func (routine_id (routine_name), {operand})
EU>>
EU>>EU>Now, how could I expect the binder to know to leave in the two
EU>>EU>functions above? It HAS to leave both in the code, even though it
EU>>EU>can't tell if either of them will ever be used.
EU>[...]
EU>>With this, though, a smart binder could do the following:
EU>>1. see that commands is a constant
EU>>2. see that the argument to routine_id is an element of commands
EU>>3. know to leave in any routines named in commands

EU>Well, that's theoretically true, and that sort of behavior would
EU>be desireable. But just as another example of how tricky this could
EU>get... before sending my email, I looked over the code and realized
EU>that, silly me, I had left "commands" as a local variable. Since in
EU>my example I knew it wasn't going to change, I made it a constant
EU>"for efficiency purposes."

EU>The problem is, leaving "commands" as a variable, even modifying it
EU>later on (to add other commands once the user clicks on a checkbox,
EU>etc.) is an completely valid approach.

EU>Now I doubt *I'd* write a program like this, but if it's
EU>syntactically and logically valid, why would it be wrong for someone
EU>else to do so? That's when the problems begin. The only way to get
EU>around this seems to be somehow limiting the programmer's ability to
EU>write such code--probably by eliminating the ability to pass variables
EU>to routine_id.

Not nessicarily. If the binder couldn't be sure that a particular
routine wasn't used, it would just have to include it anyway. It would
still be able to get rid of routines that it was sure wasn't used. Also,
a really smart interpreter could see where the variable is modified that
stores the names of the routines, and try to figure out what is used
from there.

EU>Sure, you could try to make the binder smarter still, but even if
EU>*this* case can be caught, the variations are nearly infinite...
EU>you'll eventually reach a point at which the binder can't handle it.
EU>Suppose your referenced routines consist of:

EU>   commandname_parametertype

EU>and the name of the function to call is constructed at runtime
EU>based on options the user selects? Or, what if you want to test
EU>individual routines by directly inputing their names and
EU>executing them?

EU>"No one does any of that!" PROBABLY true. But it's valid, isn't it?
EU>And if it's valid, then it's a situation that has to be handled.
EU>The point is, there's no way to correctly evaluate all possible
EU>contexes (?) when "routine_id (var)" is encountered. The binder
EU>would have to back up through every place where "var" is set,
EU>everywhere where a slice of "var" is set, every location where
EU>a variable that var is set to gets set. In this miniscule example
EU>alone, the binder would have to back up through:

Actually, I have used dynamic construction of routine names to spcify
the types of arguments. I did this to construct an Euphoria interpreter
for my compiled Euphoria bytecodes (I've been working on a Euphoria
assembly language and a compiler and interpreter for it). Still, a smart
binder could figure it out because it would see:

1. I start out with a constant name
2. I add either 'l' or 'v' to the end through a for loop and if
statements depending on the type of each argument.
3. The number of arguments is constant.

I agree with you, though, that if the routine name was totally
unpredictable (like using gets(0) to get a routine name), the binder
would not be able to scrap _any_ routines _in the current scope_. For
example:

include somefile.e
procedure a()
        ...
end procedure
procedure b()
        ...
end procedure
sequence name
name = gets(0)
call_proc(routine_id(name[1..length(name)-1]),{})

The binder couldn't get rid of a, b, or any global routines defined in
somefile.e. It could get rid of any non-global routines in somefile.e
that aren't referenced by any of the global routines.


EU>   routine_id (routine_name) -->
EU>   routine_name = commands[choice] -->
EU>   constant commands = {...} -->
EU>      BINDER: good, "commands" is a constant. Is "choice"? -->
EU>      choice = get_number (0) --> (assume get_number is built-in,
EU>         or things get worse...)
EU>         BINDER: no, "choice" is always undetermined. We need to
EU>            account for every element of "commands" -->
EU>   BINDER: adds routine named commands[1] to the table
EU>    ...
EU>   BINDER: adds routine named commands[length(commands)] to the table

EU>I imagine that for larger programs, or use of expressions (&, etc.),
EU>the complexity could increase quite rapidly. Even then, you're
EU>still making some assumptions that may not be valid. And again,
EU>heaven forbid that after backing through all assignments you wind
EU>up not having enough data to construct all potential literals.

EU>It seems clear that you'd be better off just leaving all routines
EU>in rather than taking this approach. You'll either wind up limiting
EU>routine_id, or only being able to do this on programs that have no
EU>calls to routine_id, or leaving open the possibility of writing
EU>programs that occasionally give "invalid routine name" errors at
EU>runtime.


EU>Rod


Jeffrey Fielding
JJProg at cyberbury.net
http://members.tripod.com/~JJProg/

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

Search



Quick Links

User menu

Not signed in.

Misc Menu