Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

Hack

 [1/21] from: rotenca::telvia::it at: 27-Dec-2001 1:34


I have found a not so standard method to find the funtion name and the code inside a function. It works also if the funtion name is local: hackme: func ["hackme" /local myself] [ error? err: disarm try [2 / 0] myself: get in err 'where print [ "my name is:" myself "^/my body is:" mold second get myself "^/my spec is:" mold third get myself ] ] x What do you think of this method? Can be considered valid in all the situations? --- Ciao Romano

 [2/21] from: sunandadh:aol at: 27-Dec-2001 20:17


Hi Romano,
> I have found a not so standard method to find the funtion name and the code > inside a function. It works also if the funtion name is local: <snip> > What do you think of this method? Can be considered valid in all the > situations?
I think it's a very clever hack! Unfortunately it doesn't work for a function in ab object: HackO: make Object! [ hackF: func ["hackF" /local myself] [ error? err: disarm try [2 / 0] myself: get in err 'where print [ "my name is:" myself "^/my body is:" mold second get myself "^/my spec is:" mold third get myself ] ] ] HackO/HackF I'm disappointed with Rebol that something as simple as "What's the name of the current function?" isn't easily available, something like: print System/Current/Function-name A few weeks back I spent a while looking through the System object for a call stack. It must exist, and does exist for "Do Script.r" but I couldn't find it normal functions . They must be hiding it from us! If RT would put the stack in the system object along with everything else, it'd make formatting useful debugging reports a lot more useful. Sunanda.

 [3/21] from: joel:neely:fedex at: 28-Dec-2001 6:22


Hi, Sunanda, [SunandaDH--aol--com] wrote:
> I'm disappointed with Rebol that something as simple as > "What's the name of the current function?" isn't easily > available, something like: > > print System/Current/Function-name >
Unfortunately, I'm too dense to parse the phrase "name of the current function", at least WRT REBOL. Consider the following:
>> f: reduce [
[ func [n] [n + 1] [ func [n] [n * n - n + 1] [ func [n] [n * n * n + 3] [ ] == [func [n][n + 1] func [n][n * n - n + 1] func [n][n * n * n + 3]]
>> foreach ff f [print ff 3]
4 7 30
>>
None of those functions even *have* a name, or rather they all have the same name, or ... hmmmm ;-) The real issue is that functions are first-class values in REBOL (i.e., just as with strings or numbers, they can be created at will, passed as arguments, returned as the result of an evaluation, etc...) As a consequence of this fact, it is as meaningful/less to talk about the "name of the current function" as it is to talk about the "name of the current 2", IMHO. -- ; sub REBOL {}; sub head ($) {@_[0]} REBOL [] # despam: func [e] [replace replace/all e ":" "." "#" "@"] ; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"} print head reverse despam "moc:xedef#yleen:leoj" ;

 [4/21] from: ammonjohnson:ya:hoo at: 28-Dec-2001 11:26


LOL you slay me!! Ammon

 [5/21] from: greggirwin:mindspring at: 28-Dec-2001 12:24


Hi Joel, et al << Unfortunately, I'm too dense to parse the phrase "name of the current function", at least WRT REBOL. >> How about "the identifier referencing the current context" then? :) While it's true that functions can be anonymous, and can also be treated as first class values, there will likely be a large body of code out there that doesn't make use of those alternatives don't you think? I haven't played with Romano's idea yet but I'm grateful for anything that can help provide some kind of context information when an error occurs, even if it won't work 100% of the time. Something is better than nothing IMO. --Gregg

 [6/21] from: sunandadh:aol at: 28-Dec-2001 14:45


Hi Joel,
> The real issue is that functions are first-class values in > REBOL (i.e., just as with strings or numbers, they can be
<<quoted lines omitted: 3>>
> current function" as it is to talk about the "name of the > current 2", IMHO.
That's clever stuff, but I think it misses the point I'd like to make. Take these three functions: FuncA: func [] [2 / 2 FuncB] FuncB: func [] [2 / 2 FuncC] FuncC: func [] [2 / 2] Change any of those 2 / 2 to 2 / 0, invoke FuncA and you'll get a message like: ** Math Error: Attempt to divide by zero ** Where: FuncC ** Near: 2 / 0 With the 'Where giving me the name of the function. The only way we know to get that name is (see Romano's original post) to force an error. That is not a first-class API in my opinion <g>. And all the more so as the 'Where field is described in the Core User Guide (2.3 Sept 2000) as reserved so we can't rely on that method long term. I agree that if a function isn't named then Rebol can't show a name....But it doesn't follow that therefore it can't give me any names at all, ever. The Rebol way? IOTYWYWTKIYBSF I'll only tell you what you want to know if you break something first Sunanda.

 [7/21] from: rotenca:telvia:it at: 28-Dec-2001 21:16


Hi Gregg and all, I forgot the un-named func, the new version of hackme follow this message. In the example below one can see that the first time the function is called, the name x is not assigned. I thinked that in a statement like: do x: does [print a] the sequence would be: 1) create func 2) assign it to x 3) do it But the 'where field of error! seems to think different. (I have not seen the message of Sunanda on this thread, it seems to me that the mailing list works bad - i receive only 2/3 message/day and often with great delay from post also 4-5 days). -------- do x: func ["hackme" /local myself] [ error? err: disarm try [2 / 0] either word? myself: get in err 'where [ print ["My name is:" :myself] myself: get myself ] [ print "Not called using a word" ] print [ "My body is:" mold second :myself "^/My spec is:" mold third :myself ] ] x --- Ciao Romano

 [8/21] from: rotenca:telvia:it at: 28-Dec-2001 21:31


Hi Sunanda and all, I've read the Sunanda msg on escribe: you are right, hackf doesn't work in your example. But the reason is not that it is defined in a object, but that it is called with a path. Seems that where uses exactly the word of the path refinement which is normally a global word. Look at these examples (which use the old version of hack): Hacko: make Object! [ hackF: func ["hackF" /local myself] [ error? probe err: disarm try [2 / 0] myself: get in err 'where print [ "my name is:" myself "^/my body is:" mold second get myself "^/my spec is:" mold third get myself ] ] hackf ] do in hacko 'hackf hacko/hackf do bind [hacko/hackf] in hacko 'self Only the third time the hack fails. --- Ciao Romano

 [9/21] from: rotenca:telvia:it at: 28-Dec-2001 22:22


HI Joel,
> The real issue is that functions are first-class values in > REBOL (i.e., just as with strings or numbers, they can be
<<quoted lines omitted: 3>>
> current function" as it is to talk about the "name of the > current 2", IMHO.
name-of-current-two: 2 ;-) --- Ciao Romano

 [10/21] from: sunandadh:aol at: 28-Dec-2001 17:11


Hi Romano,
> I've read the Sunanda msg on escribe: you are right, hackf doesn't work in > your example.
<<quoted lines omitted: 7>>
> do bind [hacko/hackf] in hacko 'self > Only the third time the hack fails.
I think you mean the 2nd fails, the first and last work. Unfortunately the 2nd is (in my work at least) just about the only way I ever write function calls to functions in objects. --- On a related subject, I'd like a way to get the name of an object. Example: MyObject: make object! [a: 0 b: 0 c: 0] MyFunc MyObject ... MyFunc: func [obj [Object!]][ if error? [obj/a] [ Print [?? "is missing its 'a' variable"] ] ; if ] ;func where we replace the "??" with the magic hack to dereference obj into MyObject . Now I know I could sort of do it like this: MyObject: make object! [a: 0 b: 0 c: 0] MyFunc "MyObject" ... MyFunc: func [obj-String [String!] /local obj][ obj: get to-word obj-string if error? try [obj/a] [ Print [Obj-string "is missing its 'a' variable"] ] ; if ] ;func But that feels like a workaround to me, and for precise functional equivalence, I need to add in the check that Obj is an object. Any ideas? Sunanda.

 [11/21] from: joel:neely:fedex at: 28-Dec-2001 17:37


Hi, Gregg, Please see my reply to similar comments from Sunanda. I'm really asking whether there's something else we might get that would be at least as useful (if not more so) than the somewhat arbitrary idea of "name". Gregg Irwin wrote:
> How about "the identifier referencing the current context" then? > :)
<<quoted lines omitted: 6>>
> when an error occurs, even if it won't work 100% of the time. > Something is better than nothing IMO.
I tend to side with Will Rogers. "It ain't what I don't know that gets me in trouble; it's what I know that ain't so!" If the something is based on a potentially misleading model of what the language is doing, then I'd rather spend my time coming up with a better something... -jn-

 [12/21] from: joel:neely:fedex at: 28-Dec-2001 17:50


Hi, again, Sunanda, [SunandaDH--aol--com] wrote:
> On a related subject, I'd like a way to get the name of an object. > Example:
<<quoted lines omitted: 8>>
> where we replace the "??" with the magic hack to dereference obj > into "MyObject".
If you really want your objects to have human-readable identities, you can add that easily: MyObject: make object! [ID: "George" a: 0 b: 0 c: 0] MyFunc: func [obj [object!]] [ if error? [obj/a] [ print [obj/ID "is missing its 'a' member"]] ] which also works in the more general, anonymous cases: MyObjects: copy [] MyProto: make object! [ID: "none" a: 0 b: 0 c: 0] repeat i 20 [ append MyObjects make MyProto [ID: join "obj-" i]] foreach ob MyObjects [MyFunc ob] for i 1 20 1 [MyFunc MyObjects/:i]
> ... for precise functional > equivalence, I need to add in the check that Obj is an object. >
Which demonstrates that: 1) REBOL really doesn't support the conventional view of objects very well, since I don't have any way to use the function argument spec to state that I only what a particular *kind* of object... 2) Perhaps the problem could be solved by making sure that MYFUNC never gets called on anything that wasn't created from an appropriate prototype -- but that's a code design issue and (see the previous point) not something that REBOL explicitly supports with language mechanisms. -jn-

 [13/21] from: joel:neely:fedex at: 28-Dec-2001 18:00


[ This is a repost, as the first attempt seems to have disappeared. If you get duplicates, please accept my apologies. ] Hi, Sunanda, [SunandaDH--aol--com] wrote:
> That's clever stuff... >
I'm not trying to be "clever" to be difficult! ;-) My concern, which I probably didn't state well, is that I'd rather see a mechanism that works for the general case of anonymous functions (even if -- and I agree with you -- the majority of code uses defined-and-named-once functions) rather than have a tool that only works in the simple cases.
> ...but I think it misses the point I'd like > to make. Take these three functions:
<<quoted lines omitted: 9>>
> we know to get that name is (see Romano's original post) to force > an error.
But, see below...
> That is not a first-class API in my opinion <g>... >
Agreed. Absolutely.
> I agree that if a function isn't named then Rebol can't show a > name....But it doesn't follow that therefore it can't give me > any names at all, ever. >
But it does raise in my mind the question of whether the name is as meaningful as some other possible information we might get. Consider the following...
>> f: reduce [
[ func [x] [x / divisor + 1] [ func [x] [x / divisor + 2] [ func [x] [x / divisor + 3] [ ] == [func [x][x / divisor + 1] func [x][x / divisor + 2] ...
>> foreach ff f [print ff 4]
3 4 5
>> divisor: 0
== 0
>> foreach ff f [print ff 4]
** Math Error: Attempt to divide by zero ** Where: ff ** Near: x / divisor + 1 Knowing that I happened to have accessed the function via the (temporary!) reference in a word named FF is of little use, if what I am really trying to do is find (and, presumably, fix) the defective code. Also, consider the following...
>> do func [x][x / divisor + 4] 5
** Math Error: Attempt to divide by zero ** Where: func [x][x / divisor + 4] ** Near: x / divisor + 4
>> g: func [n [number!]] [
[ if 0 < do func [x][x / divisor + 4] n [ [ print "positive" [ ][ [ print "non-positive" [ ] [ ]
>> g 5
** Math Error: Attempt to divide by zero ** Where: func [x][x / divisor + 4] ** Near: x / divisor + 4 in which "Where:" doesn't even have a name, because there isn't one at all. By way of contrast, let me mention the behavior of the CALLER function in Perl. It accesses information in the "stack of current subroutine calls", which includes the source file name and line number of each pending evaluation. Knowing where a function is defined seems to me to be at least as useful as what name the caller may have used to get to it... Just my $0.02... -jn-

 [14/21] from: al:bri:xtra at: 29-Dec-2001 11:55


> How about "the identifier referencing the current context" then?
'self is pretty good.
>> o: make object! [m: 123] >> probe o/self
make object! [ m: 123 ]
>>
Andrew Martin ICQ: 26227169 http://valley.150m.com/

 [15/21] from: joel:neely:fedex at: 28-Dec-2001 17:34


Hi, Sunanda, [SunandaDH--aol--com] wrote:
> That's clever stuff... >
I'm not trying to be "clever" to be difficult! ;-) My concern, which I probably didn't state well, is that I'd rather see a mechanism that works for the general case of anonymous functions (even if -- and I agree with you -- the majority of code uses defined-and-named-once functions) rather than have a tool that only works in the simple cases.
> ...but I think it misses the point I'd like > to make. Take these three functions:
<<quoted lines omitted: 9>>
> we know to get that name is (see Romano's original post) to force > an error.
But, see below...
> That is not a first-class API in my opinion <g>... >
Agreed. Absolutely.
> I agree that if a function isn't named then Rebol can't show a > name....But it doesn't follow that therefore it can't give me > any names at all, ever. >
But it does raise in my mind the question of whether the name is as meaningful as some other possible information we might get. Consider the following...
>> f: reduce [
[ func [x] [x / divisor + 1] [ func [x] [x / divisor + 2] [ func [x] [x / divisor + 3] [ ] == [func [x][x / divisor + 1] func [x][x / divisor + 2] ...
>> foreach ff f [print ff 4]
3 4 5
>> divisor: 0
== 0
>> foreach ff f [print ff 4]
** Math Error: Attempt to divide by zero ** Where: ff ** Near: x / divisor + 1 Knowing that I happened to have accessed the function via the (temporary!) reference in a word named FF is of little use, if what I am really trying to do is find (and, presumably, fix) the defective code. Also, consider the following...
>> do func [x][x / divisor + 4] 5
** Math Error: Attempt to divide by zero ** Where: func [x][x / divisor + 4] ** Near: x / divisor + 4
>> g: func [n [number!]] [
[ if 0 < do func [x][x / divisor + 4] n [ [ print "positive" [ ][ [ print "non-positive" [ ] [ ]
>> g 5
** Math Error: Attempt to divide by zero ** Where: func [x][x / divisor + 4] ** Near: x / divisor + 4 in which "Where:" doesn't even have a name, because there isn't one at all. By way of contrast, let me mention the behavior of the CALLER function in Perl. It accesses information in the "stack of current subroutine calls", which includes the source file name and line number of each pending evaluation. Knowing where a function is defined seems to me to be at least as useful as what name the caller may have used to get to it... Just my $0.02... -jn-

 [16/21] from: sunandadh:aol at: 28-Dec-2001 19:35


Hi Joel,
> Knowing that I happened to have accessed the function via the > (temporary!) reference in a word named FF is of little use, if what > I am really trying to do is find (and, presumably, fix) the defective > code.
(Replying to several emails in one go, and may losing part of the thread in the process). Absolutely, I agree. I want first-class diagnostic information, and some of my questions over the past couple of weeks have been about this (e.g. the thread on "Better Error Messages?" We probably have different sets of priorities. I'll tell you mine, so you can see where I'm coming from (and then you can tell me where to go!). I'm still trying out Rebol, wanting to see if it is possible to build largish applications with this basic structure: Rebol [] Do Preparation ShutDown: false While [not ShutDown] [ if Error? Try [Do RunApplication] [If Error? Try [Do ReportIncident Do AttemptRecovery ] ;try [ShutDown: True] ] ;if ] ;while Where: --Preparation does what ever is necessary in advance for error recovery and quality control (For example, I've built one pilot application which checksums the *.r sources to ensure the distribution set is consistent and untampered with). RunApplication is the payload (the pilot is about 6,000 lines of Rebol as measured out of Mold). ReportIncident should dump (or email or whatever) scads of useful stuff about where and why we've failed: failing function name, complete call stack, status of ports, maybe molds of crucial data structures). This is the weakest part of the pilot. it doesn't do much more than print the error object. And that gives barely a hint of where in the 6000 lines we're a-pumping mud. AttemptRecovery is application-specific code to repair (or direct the user to repair) the damage. I've been conscientiously putting bugs into code for over 30 years now, and even back then the first thing a diagnostic tool would tell me is "last known function call was X. Call stack is ...". Maybe I'm hopelessly old-fashioned butI can't believe the programming world has made so much progress that these things are now impossible <wry g>. I've toyed with ideas like object identifiers (as suggested in another of you emails), but that only works for my objects, not for any third-party ones I might be using (unless it becomes a standard method). And I've experimented with hand-coding a call stack: Anyfunc: [...] [ Stack "AnyFunc" .... Unstack Return true ] Where Stack and Unstack simple append/remove the string in a global block. But it's a real hassle to remember to do it for every return statement. I think maybe the real problem (from my perspective) is that RT haven't delivered what is needed in the field as opposed to the lab. But they are not far off: if they action a couple of feedback requests, I'll be very happy. Sunanda.

 [17/21] from: rotenca:telvia:it at: 29-Dec-2001 2:03


Hi Sunanda,
> > Only the third time the hack fails. > > I think you mean the 2nd fails, the first and last work.
No, the third: Hacko: make Object! [ hackF: func ["hackF" /local myself] [ error? probe err: disarm try [2 / 0] myself: get in err 'where print [ "my name is:" myself "^/my body is:" mold second get myself "^/my spec is:" mold third get myself ] ] hackf ; <- 1 from inside the object : works ] do in hacko 'hackf ; <- 2 : works hacko/hackf ; <- 3 : fails do bind [hacko/hackf] in hacko 'self ;<- 4 : works (if the program is not stopped by previous error) And works also if the function is called with a word local to a function or to a Use block. The only failure case is the path, but if one does not know how the function is called, he can't be sure about what the word points to. If we know that the function is defined in an object we could try to bind the word to the object context, but we must know at least a word of the context or be sure that 'self has not been redefined.
> On a related subject, I'd like a way to get the name of an object. Example: > MyObject: make object! [a: 0 b: 0 c: 0]
<<quoted lines omitted: 7>>
> where we replace the "??" with the magic hack to dereference obj into > "MyObject".
If you write the objects, you could do something like: make-ob-name: func [word [word!] spec [block!]][ set word make object! compose [(spec) self-name: (bind reduce [to-lit-word word] word)] ] make-ob-name 'foo [a: 2] probe foo probe foo/self-name probe get foo/self-name where self-name contains a word (eventually local) which is a pointer to the object. It what do RT with some Vid faces.
> Now I know I could sort of do it like this: > MyObject: make object! [a: 0 b: 0 c: 0]
<<quoted lines omitted: 8>>
> But that feels like a workaround to me, and for precise functional > equivalence, I need to add in the check that Obj is an object.
I'd not use string, because they works only with object defined in the global context (to-word creates always a global word). My try: MyFunc: func [word [word!] /local obj][ obj: get word if all [object? obj error? try [obj/a]] [ Print [mold word "is missing its 'a variable"] ] ; if ] ;func But you should check the error type to be sure. However to know if a word is defined in an object you can do a more simple: if none? in obj 'a [print ["'a is not defined in" mold 'obj]] Ciao Romano

 [18/21] from: sunandadh:aol at: 29-Dec-2001 5:06


Hi Romano,
> > > Only the third time the hack fails. > > > > I think you mean the 2nd fails, the first and last work. > > No, the third:
Thanks for the correction. In case you didn't pick it up in my earlier email, the Sept 2000 (the latest, I think) Rebol/Core User Guide says of the Error/Where field "The where field is reserved" This is the only place I can find in that manual where something is specifically designated reserved. That means your hack may not work in future versions. But I hope also it means that RT are planning to turn 'Where into a richly meaningful object of error-context information.
<snip> > If you write the objects, you could do something like: <snip>
Another nice Rebol hack! It's not immediately useful to me as I tend to have objects "two deep". I could use it at the first level: make-ob-name 'f [a: 1 b: 2] but to base an object on that, I still need to write g: make f [c: 3] g/self-name: 'g So it's as easy to follow Joel's suggestion of coding the identifier in the object. Sunanda.

 [19/21] from: rotenca:telvia:it at: 30-Dec-2001 14:38


Hi, Sunanda
> In case you didn't pick it up in my earlier email, the Sept 2000 (the
latest, At the end the mail arrived to me, with a great delay.
> I think) Rebol/Core User Guide says of the Error/Where field > > "The where field is reserved" > > This is the only place I can find in that manual where something is > specifically designated reserved.
This leaves us only with a 5 words copy of source in Near.
> It's not immediately useful to me as I tend to have objects "two deep". I > could use it at the first level: > > make-ob-name 'f [a: 1 b: 2] > > but to base an object on that, I still need to write > > g: make f [c: 3] g/self-name: 'g
make-ob-name: func [word [word!] type [object! datatype!] spec [block!]][ set word make type compose [self-name: (bind reduce [to-lit-word word] word) (spec)] ] But this is only an example. There are many methods to works with these kind of things. You could keep also an history of names of derived object in self-name, using a block instead of a word. --- Ciao Romano

 [20/21] from: sunandadh:aol at: 30-Dec-2001 15:52


Hi Romano,
> I forgot the un-named func, the new version of hackme follow this message. <snip>
Another case of unnamed functions is VID action facets. Here I've adapted you code to work in that case, I don't know if there is another way to specify a /local in a Vid action facet, but I've used 'Use to get the same effect. otherwise, it's all your code. unview/all view layout [ button "Print me" [ use [err myself] [ error? err: disarm try [2 / 0] either word? myself: get in err 'where [ print ["My name is:" :myself] myself: get myself ] [ print "Not called using a word" ] print [ "My body is:" mold second :myself "^/My spec is:" mold third :myself ] ] ;use ] ; action ] ;layout Though it would be kinda neat if the Face was assigned to a variable and the code could print that variable name! Print-Button: Button "Print me" [...?code?...] Prints "My name is Print-Button/Action" But that's beyond my skills Sunanda.

 [21/21] from: rotenca:telvia:it at: 31-Dec-2001 2:13


Hi Sunanda,
> Here I've adapted you code to work in that case, I don't know if there is > another way to specify a /local in a Vid action facet, but I've used 'Use to
Good choice, i think. BTW, to change the spec of all action func, you could change the function: face/multi/block: func[face blk][ if pick blk 1 [ face/action: func [face value] pick blk 1 if pick blk 2 [face/alt-action: func [face value] pick blk 2] ] ] or change directly the face/action func after creation. --- Ciao Romano

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted