1. converting v3 to v4: traps
- Posted by AndySerpa Jan 24, 2011
- 1518 views
Ok, so I'm trying to get myself into pure eu4.0 mode so I've got to convert my v3.1 programs and libraries to work with new version. After converting some variable names of previously unreserved words that are now reserved (label, loop, etc) to new names, I found that the overloading of built-ins causes bugs in the new version, but with no warning or easy way to find where.
To explain, in some cases I was overriding a built-in routine with a new global routine, i.e. the old way to do that
procedure my_task_schedule(atom tid, object sched) task_schedule(tid,sched) -- call real built-in task_schedule end procedure global procedure task_schedule(atom tid, object sched) -- override built-in -- blah blah my enhancements my_task_schedule(tid,sched) -- blah blah end procedure
And that "works" in v4 (gives no error), but doesn't work the same way because any call to "task_schedule" (which is global) outside this file will still call the built-in, unless I declare this version "override" instead of global. (If called from a later point within the same file, it works as before.) Since no error is given and no crash is guaranteed, this could lead to some nasty bugs with converted programs.
Anyway, I know I've got a few of these around in my libraries, and I can think of some others in 3rd party libraries (i.e. Method Euphoria). But there may be some I don't remember. Any easy and foolproof way to find them? I think there are a few programs around that will list all your declarations, or is there a tool somewhere I don't know about? (I normally don't use IDEs or anything, just pure TextPad w/ syntax highlighting.)
Also, a related question that also could cause some weird problems with converted programs in rare cases:
In v4 you are allowed to call a function that is declared later in the file, but if it is a built-in it will prefer the built-in. If it is a user-declared function, it will prefer the local version (declared below) even if there is a global version declared in another file (which is included "above"). This seems a bit inconsistent, but whatever, do I have this right?
In other words:
puts(1,"Hello") override puts(integer i, sequence s) eu:puts(i,s) eu:puts(i,"\nOVERRIDDEN PUTS!\n") end procedure
The above will just output "Hello" since it prefers the built-in. (Works the same as v3.1 if "override" is changed to "global".)
include file_with_other_procedure_called_myputs_declared_as_global.e myputs(1,"Hello") procedure myputs(integer i, sequence s) eu:puts(i,s) eu:puts(i,"\nOVERRIDDEN PUTS!\n") end procedure
So in this variant above, let's assume in the included file there is another "global myputs". Even though it is "above", v4 will now prefer the local version below. And even if the local version is also declared global (yes, I know, don't use global anymore, but just go with me here) it will prefer the local and give no namespace error or warning. Which means in rare cases this will also break v3.1 code that is counting on the "only can see above" behavior of that version, but without necessarily throwing an error.
Also, I didn't test it, but I assume if I do a routine_id("myputs") in that same spot I'm going to get the routine number for the same version as it is calling in that spot? (It is likely that any such problems caused by these new scoping rules with old code will involve a routine_id.)
Any good way to track these traps down so I can run my old programs safely? (And yes, what may be "rare" might not be so rare with me because I do all kinds of crazy stuff with routine_ids and overriding of built-ins.)
And while we're at it, any other things not covered here that could be lying in wait when converting an old program or library? (i.e. won't necessarily crash, but will give different behavior than v3.1)
2. Re: converting v3 to v4: traps
- Posted by ArthurCrump Jan 24, 2011
- 1440 views
Can I suggest that the Euphoria development team add some features which would help to run V3 programs; for example:
without forward_reference
Arthur
3. Re: converting v3 to v4: traps
- Posted by mattlewis (admin) Jan 24, 2011
- 1448 views
And that "works" in v4 (gives no error), but doesn't work the same way because any call to "task_schedule" (which is global) outside this file will still call the built-in, unless I declare this version "override" instead of global. (If called from a later point within the same file, it works as before.) Since no error is given and no crash is guaranteed, this could lead to some nasty bugs with converted programs.
It probably makes sense to throw a warning when something with the same name as a built-in is declared not as override.
Anyway, I know I've got a few of these around in my libraries, and I can think of some others in 3rd party libraries (i.e. Method Euphoria). But there may be some I don't remember. Any easy and foolproof way to find them? I think there are a few programs around that will list all your declarations, or is there a tool somewhere I don't know about? (I normally don't use IDEs or anything, just pure TextPad w/ syntax highlighting.)
Also, a related question that also could cause some weird problems with converted programs in rare cases:
In v4 you are allowed to call a function that is declared later in the file, but if it is a built-in it will prefer the built-in. If it is a user-declared function, it will prefer the local version (declared below) even if there is a global version declared in another file (which is included "above"). This seems a bit inconsistent, but whatever, do I have this right?
In other words:
puts(1,"Hello") override puts(integer i, sequence s) eu:puts(i,s) eu:puts(i,"\nOVERRIDDEN PUTS!\n") end procedure
The above will just output "Hello" since it prefers the built-in. (Works the same as v3.1 if "override" is changed to "global".)
I think this should be considered a bug, since it works differently than the way other scopes are resolved.
Also, I didn't test it, but I assume if I do a routine_id("myputs") in that same spot I'm going to get the routine number for the same version as it is calling in that spot? (It is likely that any such problems caused by these new scoping rules with old code will involve a routine_id.)
Yes, you should get the same thing either via a direct call or routine_id.
Any good way to track these traps down so I can run my old programs safely? (And yes, what may be "rare" might not be so rare with me because I do all kinds of crazy stuff with routine_ids and overriding of built-ins.)
First, start with the -strict command line switch, which turns on all warnings. This might be pretty large, especially for big GUI programs (the extra parameters in event handlers that are often not used). There is a way to fine tune this, though I'm not particularly familiar with how to do this.
You might also take a look at eudis, a new tool that comes with euphoria. It can produce disassembled version of the IL code that allows you to see very low level details, which can be very useful for debugging or tuning performance. However, it can also produce some html documentation, including call graphs for your program. These might be very useful to examine what's going on with your overrides.
Basically,
$ eudis --html myapp.ex...will get you the html output. In order to get the call graphs, you'll need to have Graphviz installed.
Matt
4. Re: converting v3 to v4: traps
- Posted by AndySerpa Jan 24, 2011
- 1358 views
On a side note, the built-ins really should also have routine_ids for consistency. Seems kinda silly to have to make wrapper functions to call them indirectly...
5. Re: converting v3 to v4: traps
- Posted by petelomax Jan 24, 2011
- 1329 views
On a side note, the built-ins really should also have routine_ids for consistency. Seems kinda silly to have to make wrapper functions to call them indirectly...
What I think you really want is a std/builtins.e that defines such wrappers.