Evaluate inequality in Pharo - smalltalk

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).

Related

Smalltalk - is there something similar to && from C?

I have to write a pure-object Smalltalk program, in which I need to evaluate conditions until one of them fails. I know that in C, we can use the && operator for this, and conditions only get evalutated if necessary.
Is there something similar in Smalltalk?
Conditional "anding" can be achieved by using the & message, or the and: message.
firstBooleanExpression & secondBooleanExpression
ifTrue: [ 'do something' ].
Using & as show above, the second part of the condition (secondBooleanExpression) is evaluated regardless of whether the first half evaluates to true or false.
(firstBooleanExpression and: [secondBooleanExpression])
ifTrue: [ 'do something' ].
Using and:, on the other hand, the second part is only evaluated if the first half evaluates to true. Typically you'd use this form, unless you explicitly wanted to evaluate the second half.
The same principle applies to or:.
If I understand your question, you're looking for something like this:
[ <condition> ] whileTrue: [ <loop body> ].
#whileTrue: is not a keyword of course and you could implement it yourself (look at the implementation in your Smalltalk of choice and be enlightened :)).
If you don't need a loop but are simply looking for a way to express conditionals then #ifTrue:, #ifFalse:, #ifTrue:ifFalse: and #ifFalse:ifTrue: are your friends. Examples:
myCollection isEmpty ifTrue: [ Transcript open; show: 'empty'; cr ].
myCollection isEmpty ifFalse: [ Transcript open; show: 'not empty' cr ].
myBoolean
ifTrue: [ Transcript open; show: 'true'; cr ]
ifFalse: [ Transcript open; show: 'false'; cr ].

When I use error? and try, err need a value

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.

Determine type of a variable in Tcl

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.

Why can't a built-in function be overridden in Rebol?

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.

Smalltalk and Assertions

Tryng out some smalltalk + TDD + "good practices" I've run into a kinda ugly block:
How do I do an assertion in GNU Smalltalk?
I'm just looking for a simple ifFalse: [Die] kind of thing
This is the code for assert: from Squeak (which I recommend you use rather than GNU):
assert: aBlock
"Throw an assertion error if aBlock does not evaluates to true."
aBlock value
ifFalse: [AssertionFailure signal: 'Assertion failed']
as well as
self assert: [ ... some block ]
works for blocks & non-blocks, since sending #value to Object returns self.
It has been suggested above to add #assert: to Object, but rather I'd add #assert to BlockClosure (or whatever [] class is in GNU Smalltalk).
assert
this value ifFalse: [AssertionFailure signal: 'Assertion failed']
and thus use as in
[ value notNil ] assert.
[ value > 0 ] assert.
[ list isEmpty not ] assert.
etcetera.
It is simple. In your test methods you write:
self assert: 1 + 1 = 2
But first you need to create a test class as a subclass of TestCase (in Squeak), for example:
TestCase subclass: #MyTest
Here you write testing methods, which names must always start with 'test', for instance :
testBasicArithmetics
self assert: 1 + 1 = 2