I have created this
cloneset: :set
set: func[word [word!] value][
if/else (type? get word) = list! [
print "list is immutable"
][
cloneset word value
protect word
]
]
protect 'cloneset
protect 'set
I have this error when defining the val function with the new set function:
val: func[word [word!] value][
set word value
protect word
value
]
>> val: func[word [word!] value][
[ set word value
[ protect word
[ value
[ ]
** Script Error: set has no refinement called any
** Where: throw-on-error
** Near: if error? set/any 'blk try
I don't understand why ?
When you redefine a word that's defined in system/words, you should redefine it exactly. The set word has two refinements: /pad and /any that your redefinition should also include:
cloneset: :set
set: func [
word [word! block!]
value
/any
/pad
][
either all [word? word list? get word] [
throw make error! "List is immutable!"
][
comment {
At this point you'll have to forward the arguments and refinements
of your SET method to CLONESET. This will be made much easier in R3
with the new APPLY function.
}
]
]
(I have not tested the above code at all. It should be regarded as pseudocode.)
To be sure to get the spec right, you can reuse the spec of the original function:
set: func spec-of :cloneset [
'new-implementation
]
source set
set: func [
{Sets a word, block of words, or object to specified value(s).}
word [any-word! block! object!] "Word or words to set"
value [any-type!] "Value or block of values"
/any "Allows setting words to any value."
/pad {For objects, if block is too short, remaining words are set to NONE.}
]['new-implementation]
in older versions without 'spec-of, you can use 'first in its place.
In Rebol any built-in function can be overridden. You actually did override the set function above.
However, when seeing the error you obtained you should have examined the throw-on-error function. You would have found out that in the function source code there is a call of the set function looking as follows:
set/any 'blk try ...
This call suggests that the throw-on-error function assumes the set variable to refer to a function having a /any refinement. Since your redefined version of the function does not have such a refinement, the throw-on-error function cannot call it that way and thus the error you obtained.
Generally spoken, you can redefine anything, but you have to take the responsibility for the redefinition, especially if the redefined version is not backwards compatible with the original.
Related
Since I am not aware of any inequality operator in Pharo smalltalk, it makes it difficult to check for inequality of a string. This is my current code:
[ contact password = contact confirmPassword and: firstTime = false and: (contact password = '' ifTrue:[^false])] whileFalse: [ code]
namely this part:
(contact password = '' ifTrue:[^false])
What am I doing wrong? Is there a better way to check if a string is not empty?
There is an inequality operator,
a ~= b
although it's rarely used as it is often better to just write a = b ifFalse: [ ...]
That's not all however, and: accepts a block, not a boolean
so
contact password = contact confirmPassword and: firstTime = false
should actually be
contact password = contact confirmPassword and: [ firstTime = false ]
if you want the shorthand variant, you can use &
contact password = contact confirmPassword & (firstTime = false)
The difference is that the and: block is evaluated only if the receiver is true. This is important if the and: block relies on the truthness of the the receiver, such as a ~= 0 and: [ x / a = b ]. This would be a ZeroDivide error if you used & or forgot the block.
Finally you can check string emptiness by sending it isEmpty or ifEmpty: message, e.g.
myString ifEmpty: [ ... ]
or equivalently
myString isEmpty ifTrue: [ ... ]
So you can write your condition for example as follows:
contact password = contact confirmPassword & firstTime not & contact password isEmpty ifTrue: [ ^ false ]
Pharo does have inequality:
anObject ~= otherObject
This is equivalent to
(anObject = otherObject) not
What Pharo does not have (along with any other Smalltalk or pure object language) is such thing as an "operator" (which is a mathematical function).
In Pharo, both = and ~= are not operators but simple messages you send to an object. In this case means: take object anObject and send to him the message ~= with parameter otherObject.
It has certain practical consequences like the fact that you can define your own =, ~= messages... and you can check how they are implemented (or even modify them, though I do not recommend it to you if you want to keep the system running :) )
About the empty string, you have several better ways to do it than what you are doing now, this is the simplest (and better):
aString ifEmpty: [ ^ false ].
... or you can also check for nil (sometimes you need it):
aString isEmptyOrNil ifTrue: [ ^ false ].
... or you could check size (zero means empty, isn't?):
aString size = 0 ifTrue: [ ^ false ]
There are others, but these come to mind fast. Please notice that the best way to do it is using ifEmpty: message. Also if you look for implementors of ifEmpty:, in Pharo is easy with spotter (press shift+enter) or selecting ifEmpty: and pressing cmd+m (if mac) or ctrl+m (if using linux/windows), you will find in the same class implementing it also a family of interesting messages you can use: ifEmpty:, ifNotEmpty:, etc.
EDIT: formatting.
EDIT: I would write your code like this:
[ contact password = contact confirmPassword
and: [ firstTime not
and: [ contact password notEmpty ]]]
whileFalse: [ code ]
Notice following:
the square brackets for and: parameters. This is because they are also messages (not operators) who receive a block parameter who is evaluated lazily, then making expression much more efficient.
firstTime not is equivalent (but more legible in Pharo programming style) than firstTime = false.
contact password notEmpty is how you check for empty without passing control to a block if empty happens. This is equivalent to contact password isEmpty not which is also a valid way of writing the code (but less concise).
Here my function that execute cmd as a Rebol instructions :
exec-cmd: func [
cmd [ block! ] "Rebol instructions"
/local err
] [
if error? err: try [
do cmd
] [ print mold disarm err ]
]
When I launch the function, I've encountered the following error message :
** Script Error: err needs a value
** Where: exec-cmd
** Near: if error? err: try [
do cmd
]
How can I avoid this message and manage the error ?
When the Rebol default evaluator sees a sequence of a SET-WORD! followed by a "complete" expression, it will assign the result of that expression to the named word.
However, Rebol has the ability to return a special kind of "nothing" from a function called an UNSET!. For instance:
>> type? print {What "value" does a print return?}
What "value" does a print return?
== unset!
This is different from returning a NONE! value...because if you continue the chain of evaluation, the evaluator will not allow them in assignments.
>> foo: print {This isn't legal}
This isn't legal
** Script Error: foo needs a value
** Near: foo: print "This isn't legal"
Variables cannot actually "hold a value" of type UNSET!. UNSET! is just the "value type" that you will get if you try and access a variable that is not set. Regardless of the philosophical equivalence of whether there is a none value or not, the mechanical consequence is that if you want to allow an unset! value to effectively be "assigned" you have to do that "assignment" using the set function and the /any refinement:
>> set/any 'foo (print {This works...})
This works...
== unset!
But to be able to read from the value, you can't just reference it as the variable is now undefined. You need to use the corresponding get:
>> type? get/any 'foo
== unset!
Anyway, that's the background on why you're seeing this. Your cmd presumably ended with a function that returned an UNSET!, like maybe print?
Here's an example that may be illustrative:
exec-cmd: func [
cmd [block!] "Rebol instructions"
/local err
] [
set/any 'result (try [do cmd])
case [
unset? get/any 'result [
print "Cmd returned no result"
]
function? :result [
print ["Cmd returned a function:" newline (mold :result)]
]
;-- Rebol3 only --
;
; closure? :result [
; print ["Cmd returned a closure:" newline (mold :result)]
; ]
;-- Rebol3 should be changed to match Red and not require this --
;
lit-word? :result [
print ["Cmd returned a literal word:" newline (mold :result)]
]
error? result [
print mold disarm result
]
true [
print ["Cmd returned result of type" (mold type? result)]
print ["The value was:" newline (mold result)]
]
]
]
Notice that once you've already handled the case where result might be unset, you don't have to use get/any and can just do normal access.
There is a foundational issue in the way the interpreter works, that if a word is bound to a FUNCTION! value (also the CLOSURE! values in Rebol3) then referencing that word invokes the related code. To work around this, if you know you're in a situation where a word may hold a such a value you can use GET or the analogue of a SET-WORD! known as a GET-WORD!. These are generally considered "ugly" so it's best if you can isolate the part of the code that needs to test for such an edge case and not wind up putting colons in front of things you don't need to!
What has been deemed a design flaw is something called "lit-word decay". This necessitates the use of a GET-WORD! in Rebol2 if you have an actual literal word in your hand. In that case, your program won't crash, it just won't give you what you expect. It's explained here...it has already been changed in Red so it's certain to change for Rebol3.
Also, the concept of errors being "armed" and needing to be "disarmed" to be inspected has been eliminated in Rebol3. That doesn't affect the error? test in Rebol2 such that you'd need to use a GET-WORD!, but affected just about everything else you could do with them.
All right. I think I've covered all the cases here, but someone will correct me if I haven't!
(Note: if you're curious how to make your own function that returns an UNSET! like print does, just use exit instead of return)
>> nothing: func [value] [exit]
>> type? nothing 1020
== unset!
Use set/any and get/any to handle values that regular assignment and evaluation can't.
if error? set/any 'err try [
do cmd
] [ print mold disarm get/any 'err ]
Once the error is disarmed you can handle it normally.
I usually program by functions in an "instinctive" manner, but my current problem can be easily solved by objects, so I go ahead with this method.
Doing so, I am trying to find a way to give an object a constructor method, the equivalent of init() in python, for example.
I looked in the http://www.rebol.com/docs/core-fr/fr-index.html documentation, but I couldn't find anything relevant.
There is no special constructor function in Rebol, but there is a possibility to write ad hoc init code if you need it on object's creation in the spec block. For example:
a: context [x: 123]
b: make a [
y: x + 1
x: 0
]
So, if you define your own "constructor" function by convention in the base object, you can call it the spec block on creation. If you want to make it automatic, you can wrap that in a function, like this:
a: context [
x: 123
init: func [n [integer!]][x: n]
]
new-a: func [n [integer!]][make a [init n]]
b: new-a 456
A more robust (but bit longer) version of new-a that would avoid the possible collision of passed arguments to init with object's own words would be:
new-a: func [n [integer!] /local obj][
also
obj: make a []
obj/init n
]
You could also write a more generic new function that would take a base object as first argument and automatically invoke a constructor-by-convention function after cloning the object, but supporting optional constructor arguments in a generic way is then more tricky.
Remember that the object model of Rebol is prototype-based (vs class-based in Python and most other OOP languages), so the "constructor" function gets duplicated for each new object created. You might want to avoid such cost if you are creating a huge number of objects.
To my knowledge, there is no formal method/convention for using object constructors such as init(). There is of course the built-in method of constructing derivative objects:
make prototype [name: "Foo" description: "Bar"]
; where type? prototype = object!
My best suggestion would be to define a function that inspects an object for a constructor method, then applies that method, here's one such function that I've proposed previously:
new: func [prototype [object!] args [block! none!]][
prototype: make prototype [
if in self 'new [
case [
function? :new [apply :new args]
block? :new [apply func [args] :new [args]]
]
]
]
]
The usage is quite straightforward: if a prototype object has a new value, then it will be applied in the construction of the derivative object:
thing: context [
name: description: none
new: [name: args/1 description: args/2]
]
derivative: new thing ["Foo" "Bar"]
note that this approach works in both Rebol 2 and 3.
Actually, by reading again the Rebol Core documentation (I just followed the good old advice: "Read The French Manual"), there is another way to implement a constructor, quite simple:
http://www.rebol.com/docs/core-fr/fr-rebolcore-10.html#section-8
Of course it is also in The English Manual:
http://www.rebol.com/docs/core23/rebolcore-10.html#section-7
=>
Another example of using the self variable is a function that clones
itself:
person: make object! [
name: days-old: none
new: func [name' birthday] [
make self [
name: name'
days-old: now/date - birthday
]
]
]
lulu: person/new "Lulu Ulu" 17-May-1980
print lulu/days-old
7366
I find this quite convenient, and this way, the constructor lies within the object. This fact makes the object more self-sufficient.
I just implemented that successfully for some geological stuff, and it works well:
>> source orientation
orientation: make object! [
matrix: []
north_reference: "Nm"
plane_quadrant_dip: ""
new: func [{Constructor, builds an orientation object! based on a measurement, as given by GeolPDA device, a rotation matrix represented by a suite of 9 values} m][
make self [
foreach [a b c] m [append/only matrix to-block reduce [a b c]]
a: self/matrix/1/1
b: self/matrix/1/2
c: self/matrix/1/3
d: self/matrix/2/1
e: self/matrix/2/2
f: self/matrix/2/3
g: self/matrix/3/1
h: self/matrix/3/2
i: self/matrix/3/3
plane_normal_vector: reduce [matrix/1/3
matrix/2/3
matrix/3/3
]
axis_vector: reduce [self/matrix/1/2
self/matrix/2/2
self/matrix/3/2
]
plane_downdip_azimuth: azimuth_vector plane_normal_vector
plane_direction: plane_downdip_azimuth - 90
if (plane_direction < 0) [plane_direction: plane_direction - 180]
plane_dip: arccosine (plane_normal_vector/3)
case [
((plane_downdip_azimuth > 315) or (plane_downdip_azimuth <= 45)) [plane_quadrant_dip: "N"]
((plane_downdip_azimuth > 45) and (plane_downdip_azimuth <= 135)) [plane_quadrant_dip: "E"]
((plane_downdip_azimuth > 135) and (plane_downdip_azimuth <= 225)) [plane_quadrant_dip: "S"]
((plane_downdip_azimuth > 225) and (plane_downdip_azimuth <= 315)) [plane_quadrant_dip: "W"]
]
line_azimuth: azimuth_vector axis_vector
line_plunge: 90 - (arccosine (axis_vector/3))
]
]
repr: func [][
print rejoin ["Matrix: " tab self/matrix
newline
"Plane: " tab
north_reference to-string to-integer self/plane_direction "/" to-string to-integer self/plane_dip "/" self/plane_quadrant_dip
newline
"Line: " tab
rejoin [north_reference to-string to-integer self/line_azimuth "/" to-string to-integer self/line_plunge]
]
]
trace_te: func [diagram [object!]][
len_queue_t: 0.3
tmp: reduce [
plane_normal_vector/1 / (square-root (((plane_normal_vector/1 ** 2) + (plane_normal_vector/2 ** 2))))
plane_normal_vector/2 / (square-root (((plane_normal_vector/1 ** 2) + (plane_normal_vector/2 ** 2))))
]
O: [0 0]
A: reduce [- tmp/2
tmp/1
]
B: reduce [tmp/2 0 - tmp/1]
C: reduce [tmp/1 * len_queue_t
tmp/2 * len_queue_t
]
L: reduce [- axis_vector/1 0 - axis_vector/2]
append diagram/plot [pen black]
diagram/trace_line A B
diagram/trace_line O C
diagram/trace_line O L
]
]
>> o: orientation/new [0.375471 -0.866153 -0.32985 0.669867 0.499563 -0.549286 0.640547 -0.0147148 0.767778]
>> o/repr
Matrix: 0.375471 -0.866153 -0.32985 0.669867 0.499563 -0.549286 0.640547 -0.0147148 0.767778
Plane: Nm120/39/S
Line: Nm299/0
Another advantage of this way is that variables defined by the "new" method directly belongs to the object "instance" (I ran into some trouble, with the other methods, having to mention self/ sometimes, having to initialize variables or not).
I'm trying to find out how OO works in REBOL. Prototypical indeed. Yesterday I came across this page, which inspired me to the classical OO model below, without duplication of functions:
;---- Generic function for class or instance method invocation ----;
invoke: func [
obj [object!]
fun [word!]
args [block!]
][
fun: bind fun obj/.class
;---- Class method names start with a dot and instance method names don't:
unless "." = first to-string fun [args: join args obj]
apply get fun args
]
;---- A class definition ----;
THIS-CLASS: context [
.class: self ; the class refers to itself
;---- Class method: create new instance ----;
.new: func [x' [integer!] /local obj] [
obj: context [x: x' .class: none] ; this is the object definition
obj/.class: self/.class ; the object will refer to the class
; it belongs to
return obj
]
;---- An instance method (last argument must be the instance itself) ----;
add: func [y obj] [
return obj/x + y
]
]
Then you can do this:
;---- First instance, created from its class ----;
this-object: THIS-CLASS/.new 1
print invoke this-object 'add [2]
;---- Second instance, created from from a prototype ----;
that-object: this-object/.class/.new 2
print invoke that-object 'add [4]
;---- Third instance, created from from a prototype in another way ----;
yonder-object: invoke that-object '.new [3]
print invoke yonder-object 'add [6]
;---- Fourth instance, created from from a prototype in a silly way ----;
silly-object: yonder-object/.class/.class/.class/.class/.new 4
print silly-object/.class/add 8 silly-object
print this-object/.class/add 8 silly-object
print THIS-CLASS/add 8 silly-object
(It works in REBOL 2, and prints 3, 6, 9, 12, 12, 12 successively.) Hardly any overhead. Probably it won't be difficult to find a dozen of other solutions. Exactly that is the real problem: there are too many ways to do it. (Maybe we'd better use LoyalScript.)
I'm looking for a way to find the type of a variable in Tcl. For example if I have the variable $a and I want to know whether it is an integer.
I have been using the following so far:
if {[string is boolean $a]} {
#do something
}
and this seems to work great for the following types:
alnum, alpha, ascii, boolean, control, digit, double, false, graph, integer, lower, print, punct, space, true, upper, wordchar, xdigit
However it is not capable to tell me if my variable might be an array, a list or a dictionary. Does anyone know of a way to tell if a variable is either of those three?
Tcl's variables don't have types (except for whether or not they're really an associative array of variables — i.e., using the $foo(bar) syntax — for which you use array exists) but Tcl's values do. Well, somewhat. Tcl can mutate values between different types as it sees fit and does not expose this information[*]; all you can really do is check whether a value conforms to a particular type.
Such conformance checks are done with string is (where you need the -strict option, for ugly historical reasons):
if {[string is integer -strict $foo]} {
puts "$foo is an integer!"
}
if {[string is list $foo]} { # Only [string is] where -strict has no effect
puts "$foo is a list! (length: [llength $foo])"
if {[llength $foo]&1 == 0} {
# All dictionaries conform to lists with even length
puts "$foo is a dictionary! (entries: [dict size $foo])"
}
}
Note that all values conform to the type of strings; Tcl's values are always serializable.
[EDIT from comments]: For JSON serialization, it's possible to use dirty hacks to produce a “correct” serialization (strictly, putting everything in a string would be correct from Tcl's perspective but that's not precisely helpful to other languages) with Tcl 8.6. The code to do this, originally posted on Rosetta Code is:
package require Tcl 8.6
proc tcl2json value {
# Guess the type of the value; deep *UNSUPPORTED* magic!
regexp {^value is a (.*?) with a refcount} \
[::tcl::unsupported::representation $value] -> type
switch $type {
string {
# Skip to the mapping code at the bottom
}
dict {
set result "{"
set pfx ""
dict for {k v} $value {
append result $pfx [tcl2json $k] ": " [tcl2json $v]
set pfx ", "
}
return [append result "}"]
}
list {
set result "\["
set pfx ""
foreach v $value {
append result $pfx [tcl2json $v]
set pfx ", "
}
return [append result "\]"]
}
int - double {
return [expr {$value}]
}
booleanString {
return [expr {$value ? "true" : "false"}]
}
default {
# Some other type; do some guessing...
if {$value eq "null"} {
# Tcl has *no* null value at all; empty strings are semantically
# different and absent variables aren't values. So cheat!
return $value
} elseif {[string is integer -strict $value]} {
return [expr {$value}]
} elseif {[string is double -strict $value]} {
return [expr {$value}]
} elseif {[string is boolean -strict $value]} {
return [expr {$value ? "true" : "false"}]
}
}
}
# For simplicity, all "bad" characters are mapped to \u... substitutions
set mapped [subst -novariables [regsub -all {[][\u0000-\u001f\\""]} \
$value {[format "\\\\u%04x" [scan {& } %c]]}]]
return "\"$mapped\""
}
Warning: The above code is not supported. It depends on dirty hacks. It's liable to break without warning. (But it does work. Porting to Tcl 8.5 would require a tiny C extension to read out the type annotations.)
[*] Strictly, it does provide an unsupported interface for discovering the current type annotation of a value in 8.6 — as part of ::tcl::unsupported::representation — but that information is in a deliberately human-readable form and subject to change without announcement. It's for debugging, not code. Also, Tcl uses rather a lot of different types internally (e.g., cached command and variable names) that you won't want to probe for under normal circumstances; things are rather complex under the hood…
The other answers all provide very useful information, but it's worth noting something that a lot of people don't seem to grok at first.
In Tcl, values don't have a type... they question is whether they can be used as a given type. You can think about it this way
string is integer $a
You're not asking
Is the value in $a an integer
What you are asking is
Can I use the value in $a as an integer
Its useful to consider the difference between the two questions when you're thinking along the lines of "is this an integer". Every integer is also a valid list (of one element)... so it can be used as either and both string is commands will return true (as will several others for an integer).
If you want to deal with JSON then I highly suggest you read the JSON page on the Tcl wiki: http://wiki.tcl.tk/json.
On that page I posted a simple function that compiles Tcl values to JSON string given a formatting descriptor. I also find the discussion on that page very informative.
For arrays you want array exists
for dicts you want dict exists
for a list I don't think there is a built in way prior to 8.5?, there is this from http://wiki.tcl.tk/440
proc isalist {string} {
return [expr {0 == [catch {llength $string}]}]
}
To determine if a variable is an array:
proc is_array {var} {
upvar 1 $var value
if {[catch {array names $value} errmsg]} { return 1 }
return 0
}
# How to use it
array set ar {}
set x {1 2 3}
puts "ar is array? [is_array ar]"; # ar is array? 1
puts "x is array? [is_array x]"; # x is array? 0
For the specific case of telling if a value is usable as a dictionary, tcllib's dicttool package has a dict is_dict <value> command that returns a true value if <value> can act as one.
When typing in rebol console
do read http://askcodegeneration.com/csharp/simple-class/
I get get-access-modifier called twice:
Access modifier:
1. private: member can be accessed only by code in the same class
2. protected: member can be accessed only by code in the same class or in a derived class
3. internal: member can be accessed only by code in the same assembly
4. public: member can be accessed by code in the same assembly or another assembly that references it choice (by default 1):
Access modifier:
1. private: member can be accessed only by code in the same class
2. protected: member can be accessed only by code in the same class or in a derived class
3. internal: member can be accessed only by code in the same assembly
4. public: member can be accessed by code in the same assembly or another assembly that references it choice (by default 1):
Whereas it is only mentioned once in the source code:
append fields-template-output form reduce [
(to-word get-access-modifier) field-layout
]
I really can't see why, can you ?
Original code here (Internet Archive)
Yes. There is only one call to it, but it's inside of a foreach. Your default is two fields, so you get asked twice. Enter more, you'll get asked more.
While you could (and probably should) do the obvious thing of saving it in a variable, Rebol has other ways. For instance you could compose the block of code:
foreach field-layout fields-layout COMPOSE/DEEP [
append fields-template-output " "
append fields-template-output form reduce [
to-word (get-access-modifier) field-layout
]
append fields-template-output ";"
append fields-template-output newline
]
The composition runs once, looks deep for the parentheses in the block, and evaluates the code. (Kind of how parse does when it sees parentheses). The rest is left alone. So the block with the substitutions done is what's passed into FOREACH to run the loop.
Just a nuance of how you could have a call that appears to be inside a loop and yet is executed only once. I wouldn't suggest using it for something like this.
What I would suggest is studying making things less redundant in your code, by learning some more Rebol primitives like REJOIN...which builds a series out of a block. The series type will match whatever the first type it sees is (or a string if the first element is not a series):
modifier: get-access-modifier ;-- called only once, stored in variable
foreach field-layout fields-layout [
append fields-template-output rejoin [
" "
(to-string modifier)
field-layout
";"
newline
]
]
To solve the problem I have used static var to detect that it is executed only once (thanks to Sunanda tips is it possible to have static variable inside a rebol function? ).
ask-params: function [config-file [file!] default-class-name default-fields] [
;config-file: %askcodegeneration.com/csharp/simple-class/simple-class.params.txt
either value? 'class-name [
ans: ask rejoin ["class name" " (by default " class-name ")" ": "]
if ans <> "" [class-name: ans]
][
class-name: default-class-name
ans: ask rejoin [{class name (default "} class-name {"): }]
if ans <> "" [class-name: ans]
]
either exists? it: config-file [
params-block: copy load it
][
params-block: []
]
either res: find params-block class-name [
fields: pick res 2
print [ class-name "found in" it]
][
fields: default-fields
ans: ask rejoin [{fields (by default } {"} fields {"} {): }]
if ans <> "" [fields: ans]
new-param: reduce [
mold class-name
mold fields
]
either not exists? config-file [
create-directory "askcodegeneration.com/csharp/simple-class/"
write/append config-file reform new-param
][
write/append config-file reform [newline new-param]
]
]
append ret-value: [] class-name
append ret-value fields
ret-value
]