1. init.e - standard library candidate
- Posted by mattlewis (admin) Mar 09, 2013
- 1741 views
I came up with a small file that makes it easier to make code (especially GUI code) more modular. Think of a Win32Lib or wxEuphoria application, where you would create all of your widgets and assign them to constants. This gets really unwieldy for large apps. And when you start splitting code into multiple files, you have to be careful that they're included in the right order so that things get initialized properly.
So I came up with init.e, and I've found myself using it in lots of projects, and it seems like the sort of thing others might find useful:
namespace init include std/map.e map init_routines = map:new() export procedure register( sequence name, integer rid = routine_id("init") ) map:put( init_routines, name, rid ) end procedure export procedure ensure( sequence name ) integer rid = map:get( init_routines, name, -1 ) if rid != -1 then map:remove( init_routines, name ) call_proc( rid, {} ) end if end procedure export procedure all() sequence r = map:pairs( init_routines ) for i = 1 to length(r) do if map:has( init_routines, r[i][1] ) then map:remove( init_routines, r[i][1] ) call_proc( r[i][2], {} ) end if end for map:clear( init_routines ) end procedure
The idea is that you call init:register( "some name" ) (it defaults to a procedure named init(), but you can put whatever you want). And then inside of you init's, you can call init:ensure( "some dependency" )), which will cause that init routine to be called if it hasn't already.
And you just call init:all() at the bottom of your main program, or just before you call WinMain() or whatever.
Matt
2. Re: init.e - standard library candidate
- Posted by EUWX Mar 09, 2013
- 1722 views
I came up with a small file that makes it easier to make code (especially GUI code) more modular. Think of a Win32Lib or wxEuphoria application, where you would create all of your widgets and assign them to constants. This gets really unwieldy for large apps. And when you start splitting code into multiple files, you have to be careful that they're included in the right order so that things get initialized properly.
So I came up with init.e, and I've found myself using it in lots of projects, and it seems like the sort of thing others might find useful:
The idea is that you call init:register( "some name" ) (it defaults to a procedure named init(), but you can put whatever you want). And then inside of you init's, you can call init:ensure( "some dependency" )), which will cause that init routine to be called if it hasn't already.
And you just call init:all() at the bottom of your main program, or just before you call WinMain() or whatever.
Matt
Looks nice. But I am a dimwit. is there a possibility of seeing an example or two?
Thanks
3. Re: init.e - standard library candidate
- Posted by mattlewis (admin) Mar 09, 2013
- 1730 views
I came up with a small file that makes it easier to make code (especially GUI code) more modular. Think of a Win32Lib or wxEuphoria application, where you would create all of your widgets and assign them to constants. This gets really unwieldy for large apps. And when you start splitting code into multiple files, you have to be careful that they're included in the right order so that things get initialized properly.
So I came up with init.e, and I've found myself using it in lots of projects, and it seems like the sort of thing others might find useful:
The idea is that you call init:register( "some name" ) (it defaults to a procedure named init(), but you can put whatever you want). And then inside of you init's, you can call init:ensure( "some dependency" )), which will cause that init routine to be called if it hasn't already.
And you just call init:all() at the bottom of your main program, or just before you call WinMain() or whatever.
Matt
Looks nice. But I am a dimwit. is there a possibility of seeing an example or two?
Thanks
Sure. I'm currently refactoring my wxIDE (I also have done this with the Win32Lib IDE). Here are some exerpts:
-- wxide.exw include init.e include main.e include menu.e include settings.e namespace main include wxeu/wxeud.e ... init:all() -- calls all of the initialization routines wxMain( main ) -- show the main window and start interacting with the user -- main.e include wxeu/wxeud.e include init.e init:register( "main" ) export atom main, status, win, notebook procedure init() init:ensure( "settings" ) main = create( wxFrame, {0, -1, "wxIDE", win_pos[1], win_pos[2], win_size[1], win_size[2], wx_or_all( {wxDEFAULT_FRAME_STYLE, wxNO_FULL_REPAINT_ON_RESIZE}) }) status = create( wxStatusBar, {main}) win = create( wxPanel, {main, -1, -1, -1, -1, -1, wxCLIP_CHILDREN}) notebook = create( wxNotebook, {win, -1, -1, -1, -1, -1, wxCLIP_CHILDREN}) ... end procedure -- menu.e include wxeu/wxeud.e as wx include init.e include main.e init:register( "menu" ) export atom menu_bar, file_menu, file_open, file_exit, ... procedure init() init:ensure( "main" ) init:ensure( "settings" ) menu_bar = create( wxMenuBar, {main}) file_menu = create( wxMenu, {menu_bar, "&File"}) file_new = create( wxMenuItem, {file_menu, wxID_NEW, "&New"}) file_open = create( wxMenuItem, {file_menu, wxID_OPEN,"&Open\tCtrl-O"}) file_reopen = create( wxMenuItem, {file_menu, wxID_REOPEN, "&Reopen File"}) file_close = create( wxMenuItem, {file_menu, close_id, "&Close\tCtrl-W"}) file_save = create( wxMenuItem, {file_menu, wxID_SAVE, "&Save"}) file_save_as = create( wxMenuItem, {file_menu, wxID_SAVEAS, "Save &As"}) file_save_project = create( wxMenuItem, {file_menu, new_id(), "Save &Project"}) append_separator( file_menu ) file_exit = create( wxMenuItem, {file_menu, wxID_EXIT, "E&xit"}) end procedure
The idea is to make it easy to take initialization out of the top level of execution, and especially to make it easy to keep dependencies straight. In this case, you can't create the menu until you've created the main window, etc.
Matt
4. Re: init.e - standard library candidate
- Posted by EUWX Mar 09, 2013
- 1701 views
Looks nice. But I am a dimwit. is there a possibility of seeing an example or two?
Thanks
Sure. I'm currently refactoring my wxIDE (I also have done this with the Win32Lib IDE). Here are some exerpts:
......
The idea is to make it easy to take initialization out of the top level of execution, and especially to make it easy to keep dependencies straight. In this case, you can't create the menu until you've created the main window, etc.
Matt
Thanks for the prompt reply and demo. I will work on it. I had suspended my work with euphoria and wxeuphoria, as i got carried away with the Raspberry Pi. I will have to get back to it all.
5. Re: init.e - standard library candidate
- Posted by ghaberek (admin) Mar 11, 2013
- 1596 views
export procedure register( sequence name, integer rid = routine_id("init") ) map:put( init_routines, name, rid ) end procedure
You've inadvertently solved a quandary that has been plaguing me for years: How do I pass only the name of a routine to an event handler, instead of embedding routine_id() in the function call? I had no idea that initializer values were called inline, which is what seems to make this magic work.
Quite simply...
public procedure SetHandler( atom this, atom id, atom event, sequence handler, integer rid = routine_id(handler) ) if length(handler) > 0 and rid = -1 then crash( "Routine %d not found!\n", {handler} ) end if -- store handler... end procedure -- later... SetHandler( frame, wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, "MyFrame:OnClick" )
Am I wrong, or should this work as I expect?
-Greg
6. Re: init.e - standard library candidate
- Posted by mattlewis (admin) Mar 11, 2013
- 1595 views
You've inadvertently solved a quandary that has been plaguing me for years: How do I pass only the name of a routine to an event handler, instead of embedding routine_id() in the function call? I had no idea that initializer values were called inline, which is what seems to make this magic work.
Quite simply...
public procedure SetHandler( atom this, atom id, atom event, sequence handler, integer rid = routine_id(handler) ) if length(handler) > 0 and rid = -1 then crash( "Routine %d not found!\n", {handler} ) end if -- store handler... end procedure -- later... SetHandler( frame, wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, "MyFrame:OnClick" )
Am I wrong, or should this work as I expect?
Yes:
-- foo.ex include foo.e procedure bar() end procedure foo( "bar" ) -- foo.e export procedure foo( sequence name, integer rid = routine_id( name ) ) ? rid end procedure
$ eui foo.ex 0
Success!
Matt
7. Re: init.e - standard library candidate
- Posted by petelomax Mar 16, 2013
- 1506 views
I had no idea that initializer values were called inline, which is what seems to make this magic work.
Yes:
-- foo.ex include foo.e procedure bar() end procedure foo( "bar" ) -- foo.e export procedure foo( sequence name, integer rid = routine_id( name ) ) ? rid end procedure
$ eui foo.ex 0
Success!
Matt
I suspect this is simply broken. What should the following do?
somefile.e
constant A="1" global procedure putsomething(sequence s=A) puts(1,s) end procedure
someotherfile.exw
include somefile.e constant A="2" putsomething() if getc(0) then end if
I'm quite happy that it prints 1, but that is not what was said, and routine_id is breaking scope by working...
Pete
8. Re: init.e - standard library candidate
- Posted by jimcbrown (admin) Mar 16, 2013
- 1457 views
I suspect this is simply broken.
Based on what you demonstrate below, I can understand why you would think that. After making the following analysis, I find that I concur with your suspicion, but possibly for different reasons.
What should the following do?
somefile.e
constant A="1" global procedure putsomething(sequence s=A) puts(1,s) end procedure
someotherfile.exw
include somefile.e constant A="2" putsomething() if getc(0) then end if
It should print 1, as the resolution of variable names for defaulted parameters - when the default is used - should be done in the context of the file where the routine is declared, not in the context of where it is used.
I'm quite happy that it prints 1, but that is not what was said, and routine_id is breaking scope by working...
Pete
Debatable.
Here's a modified version:
somefile.e
constant A="1" function it(sequence s) return s*1 end function global procedure putsomething(sequence s=A, sequence b=it(s), sequence c=repeat(s,10)) puts(1,s) puts(1,b) ? c end procedure
otherfile.exu
include somefile.e constant A="2" putsomething() putsomething(A)
It first prints out "11" followed by a sequence containing sequences of 49 (or "1"), but the second time around it prints out "22" etc. When a preceding defaulted parameter is overridden, and succeeding defaulted parameters which use it are not, then they should use the new caller-passed overridden value in preference to the original, defaulted value.
Thus, like repeat() and it() in the example above, a defaulted parameter that uses routine_id(s) in the same way should expect that when s is overriden, then the following parameter(s) that use routine_id(s) will use the new overidden value for s as well.
However, routine_id() is unique in that, like repeat() or it(), routine_id() relies on scoping to interpret the value of its parameter. So, what should routine_id() do? Should it use the scope where the routine is called, or the scope where the routine is defined? This only applies to routine_id(), since no other routine cares about scope in the same way when it is called.
I contend that the most natural way for this to work is that routine_id() should use the scope where the routine with the defaulted parameter is defined when no relevant variables are overidden by the caller (as the defaulted routine_id() call probably points to a local routine that may not be visible in the caller's scope), but when overriding occurs then it should use the caller's scope (as the caller probably wants to take the routine id of a local routine that was immediately defined - e.g. setHandler() and routine_id() are typically called together immediately after the declaration of the handler routine).
Based on that, I would conclude that this is indeed broken, because routine_id() always defaults to the callers scope.
Example:
somefile.e
constant A="1" constant AA="it" function it(sequence s) return s*1 end function global procedure putsomething(sequence s=A, sequence b=it(s), sequence c=repeat(s,10), sequence d=AA, integer e=routine_id(d)) puts(1,s) puts(1,b) ? c ? e end procedure
otherfile.exu
include somefile.e constant A="2" procedure AA() end procedure putsomething(A)
This prints out -1 at the end, when it should print out a valid routine_id() for the routine "it".
That said, I suspect that fixing routine_id() to work intelligently in what I contend is the most natural manner is probably very difficult, while working around this behavior is really easy.
If the current behavior is kept as is, then the caller can simply manually invoke routine_id() if the integer holding the routine id is -1 and the sequence holding the routine name is the same as the default.
Example:
constant A="1" constant AA="it" function it(sequence s) return s*1 end function global procedure putsomething(sequence s=A, sequence b=it(s), sequence c=repeat(s,10), sequence d=AA, integer e=routine_id(d)) puts(1,s) puts(1,b) ? c if equal(d, AA) and e = -1 then e = routine_id(AA) end if ? e end procedure
otherfile.exu
include somefile.e constant A="2" procedure AA() end procedure putsomething(A)
However, altering routine_id() so it always uses the scope of the callee is not useful, as the callee has no way to compenstate and discover the real routine id that is meant to be called from just the string. Instead, the integer with the routine_id() call must be overriden everytime - most likely by another handwritten routine_id() call directly in the caller (as is typically done with setHandler() ). This makes embedding a routine_id() call inside of a defaulted parameter unconditionally useless.
So, yes, maybe it is technically broken, but if it can't be fixed, then breaking it in this way is better than the alternative.
9. Re: init.e - standard library candidate
- Posted by petelomax Mar 16, 2013
- 1448 views
I suspect this is simply broken.
I find that I concur with your suspicion, but possibly for different reasons. So, what should routine_id() do? Should it use the scope where the routine is called, or the scope where the routine is defined? This only applies to routine_id(), since no other routine cares about scope in the same way when it is called.
...
Based on that, I would conclude that this is indeed broken, because routine_id() always defaults to the callers scope.
...
That said, I suspect that fixing routine_id() to work intelligently in what I contend is the most natural manner is probably very difficult, while working around this behavior is really easy.
...
However, altering routine_id() so it always uses the scope of the callee is not useful
This makes embedding a routine_id() call inside of a defaulted parameter unconditionally useless.
So, yes, maybe it is technically broken, but if it can't be fixed, then breaking it in this way is better than the alternative.
Thanks for the excellent and detailed reply.
I have figured it out now; the default expression is effectively parsed in the called context (that part I really misread), but evaluated in the callee context, which as you point out makes no difference except for routine_id().
FWIW, I plan (not particularly soon) in Phix to change routine_id to:
global function routine_id(string name, boolean use_callee_context=false) ... procedure x(integer rid=routine_id("something",true))
which would allow what I see as the required extra flexibility. The extra parameter would not be valid in top-level code.
Regards, Pete
10. Re: init.e - standard library candidate
- Posted by mattlewis (admin) Mar 17, 2013
- 1366 views
However, altering routine_id() so it always uses the scope of the callee is not useful, as the callee has no way to compenstate and discover the real routine id that is meant to be called from just the string. Instead, the integer with the routine_id() call must be overriden everytime - most likely by another handwritten routine_id() call directly in the caller (as is typically done with setHandler() ). This makes embedding a routine_id() call inside of a defaulted parameter unconditionally useless.
So, yes, maybe it is technically broken, but if it can't be fixed, then breaking it in this way is better than the alternative.
I actually didn't think this would work when I first tried it, because I recall going to a bit of effort to make variables evaluate in the routine's scope. This is especially important if the routine refers to something local that isn't visible outside of the file.
Routine id calls are somewhat special in that they transmit their calling point. I think we could make them be evaluated in a similar fashion to everything else, but I'm not certain that we'd really want to, since this is a really handy thing. And it's easy enough to get a local routine id by simply calculating it at the top level as a constant and using that as the default value.
Matt
11. Re: init.e - standard library candidate
- Posted by jimcbrown (admin) Mar 17, 2013
- 1375 views
However, altering routine_id() so it always uses the scope of the callee is not useful, as the callee has no way to compenstate and discover the real routine id that is meant to be called from just the string. Instead, the integer with the routine_id() call must be overriden everytime - most likely by another handwritten routine_id() call directly in the caller (as is typically done with setHandler() ). This makes embedding a routine_id() call inside of a defaulted parameter unconditionally useless.
So, yes, maybe it is technically broken, but if it can't be fixed, then breaking it in this way is better than the alternative.
I actually didn't think this would work when I first tried it, because I recall going to a bit of effort to make variables evaluate in the routine's scope. This is especially important if the routine refers to something local that isn't visible outside of the file.
I seem to recall that was actually a ticket for that.
Routine id calls are somewhat special in that they transmit their calling point. I think we could make them be evaluated in a similar fashion to everything else, but I'm not certain that we'd really want to, since this is a really handy thing. And it's easy enough to get a local routine id by simply calculating it at the top level as a constant and using that as the default value.
Matt
I said this already - in the part of my post that you quoted. You worded it better, though.
12. Re: init.e - standard library candidate
- Posted by mattlewis (admin) Mar 17, 2013
- 1384 views
I actually didn't think this would work when I first tried it, because I recall going to a bit of effort to make variables evaluate in the routine's scope. This is especially important if the routine refers to something local that isn't visible outside of the file.
I seem to recall that was actually a ticket for that.
Matt