Comments on: DEFAULT good and evil
The R3 team has been investigating various useful idioms for inclusion into the mezzanine.
One idiom of interest is default. It would set a value if it's not already defined. It's a replacement for this common expression:
unless value? 'word [word: value]
We've discussed various usage forms...
word: default 'word value
default word: value
default [word: value]
The advantage of these is that the set-word gets expressed (so context gets properly established.) That's something you want to keep in mind in R3.
Of course, we knew that we could not write the minimal expression:
word: default value
Right? Or... could we?
It suddenly dawned on me that it could be written! Here it is:
default: func [val /local word] [
word: back stack/block 1
if set-word? word: word/1 [
either any [not value? word none? get word][
set word val
val: get word
Not really very pretty, but functional.
It would work like this (where abc is not yet defined in context):
>> abc: default 20
>> ?? abc
>> abc: default 0
>> ?? abc
== 20 ; correct! It's already defined
However, Carl's first lesson of post-modern computing is just because we can, doesn't mean we should. CAN leads to complexity, often for complexity's sake alone (from my second lesson of PMC: complexity begets complexity.)
So... what say you? Is it good? Evil?
Dust off that Ph.D. wall ornament, and really think about it.
What about something like this?
default: func [
input [block!] "block of words and their default values, in spec-block format."
/local words value
parse input [
copy words some set-word! set value any-type! (
foreach word words [
if any [not value? word none? get/any word] [
set/any word either word? :value [get/any :value] [:value]
>> default [a: 1]
>> default [a: b: 2]
>> default [a: b: 3 c: none]
>> print [a b c]
1 2 none
>> default [a: b: 3 c: 'xxx]
>> print [a b c]
1 2 xxx
Gregg, Carl, both of your functions still require you to evaluate the default expression every time you call default. Most of the time my default is a series or other type that needs to be constructed, but only once.
As for evil, the STACK function itself is too evil for untrusted code to call if you want any kind of security model, especially if it returns a reference instead of a unbound copy.
That doesn't mean I won't be playing with it now that I know it exists in current builds. Rubs hands and grins maniacally...
I'm heartless when it comes to the value of CPU time. Sure, I'll feel a little guilty about the 0:0:0.05 wasted for every 10'000 calls I make to DEFAULT, but then I'll think how happy it makes me--and maybe other REBOLs--to have another nifty dialected func that makes our lives easier, intent clearer, and eliminates redundancy.
Or maybe I won't feel guilty after all.
I'm not talking about CPU time, I am taking about creating series that may be many megabytes. I've been writing construction functions lately. Running that code every time could result in hundreds of megabytes of unnecessary overhead - which could be a bad at times.|
Agreed. But if your default values are many megabytes, and you're constructing them, and you're in some kind of memory constrained situation, you might just have to choose not to use DEFAULT. I can't think of a time when I've been in that situation. My defaults are nearly always scalar values or an empty (or very small) series.|
Maybe I'm missing something... What's the difference between this and a compare?
What is the intended behaviour good for? For me, "default" means "initiate". Some languages (was it Pascal? :-)) required you to define the variable, before it could be used, some Basics required to set initial values. But for that, normal assignment is enough. I can understand shortcut for something like "if not value?", but then word "default" is not correct. When I say "default a", then I really mean - set this value as default, and imo substituting "protect" here, is simply wrong name for what "default" word means.|
set/if-not [a: 5 b: 6 c: "whatever"]|
Petr: I think you're wrong, DEFAULT is the correct name.
Carl: It's hard to say, the downside of this is that it looks too much "magic". It breaks the rule that arguments follow the function... Otherwise, it's quite cool, and I think you could simplify it a bit (you don't need the SET there, do you?).
Gabriele, of course I can be wrong, but I can bet you will see many novices going "huh?" for above example of:
abc: default 20 == 20; abc: default 0 = 20
My question is, if there is any stack for the value? What if I set 'abc 10? Because - in my book, what I can imagine default should do, is to reset actual value to initial one, which is not our case imo ...
Are we really in state when we can play with "useful idioms"? Aren't we missing much more important bug fixes? |
Yes Oldes, you are right. I can understand taking Carl and guys a bit of a break from deep design, although someone could point out, that 'default belongs to deep design category too :-)
GUI, protocols, modules, threading, plugins, let's continue, life is short and I want 3.0 beig out before I retire :-)
** Dust off that Ph.D. wall ornament, and really think about it.
Yeah..hahaha. thats the problem mainly with innovation ;-)
Strictly speaking is "Evil" not wrong! and "Good" not best! Where "Evil" often gets the best results will "Good" be accepted more. (thats is in the environment you place it within..) So personaly i would take "Good" because its a controlled "Evil" ;-)
Here's a solution to my concern about multiple evaluations. As a bonus, it's even more evil since it modifies the calling code.
once: func [
"Evaluates code once, returns and disappears (modifies the call in place)."
:code [block! paren!] "The code to be evaluated, once"
change/only change stack/block 1 'first reduce [set/any 'code do code]
I was really careful to ensure that the code of the call and the replacement code are both the same length, to avoid invalidating the reference to the code block inside the DO native - this kind of thing used to crash REBOL 2.
This is why the code parameter is a block or paren get-word, to prevent people from being able to calculate the argument because that expression would have an unknown number of elements in it, so removing it would change the length of the code block and invalidate the positions of every reference to that code.
Its not only usefull for default, but
i: * 2
Could that mode be inbuild? A function with access to the left value, if its a set-word? And making modifying set-words an idiom?
God, I hope not - set-words should never do more than assignment. No hidden operations!
The fact that these functions work at all is good to know, because we're going to have to fix the STACK function to make this kind of thing impossible. Everything we have demonstrated here is a security hole and a debugging nightmare.
This exists in Rebol :
set 'myword myvalue
Then, why not ...
set-default: func [
word [word!] value
unless value? word [ set word value ]
set-default 'myword value
I'm also a bit afraid of using STACK. For debugging, it could be difficult to understand origin of a problem.
Going further than Goldevil, why don't consider "default" as a refinement of the "set" function?|
[OFF Topic - help needed]
I have this:
msg: import-email message
The content is displayed along with other info.
How do I display only the *actual* body of the message ?
Thanks! (Sorry for the off-topic)
|Free zip program , Unzip|
Very lengthy but useful blog. You wrote in the beginning that you had put huge data in the text area box, so blog became really complex. I think if a blog contains huge data then that should be zipped in a file and should be placed in the same text area, so that if your blog persuades the reader to look through the data, he can unzip that right here. This way your blog doesn’t hold a complex appearance. For this zipping, unzipping right at your page, here is a website named www.krunchit.net where you can compress and decompress ten files online in one shot. |
Post a Comment:
You can post a comment here. Keep it on-topic.