FFI and apicall/cdecl type
Andreas Raab
andreas.raab at gmx.de
Wed Jul 19 19:05:22 UTC 2006
Mathieu SUEN wrote:
> A think that it is cool to see somthing like this:
>
> aExtType := descriptorClass externalType: aToken value ifAbsent: [
> self interactive ifTrue:[^nil].
> "otherwise go over it silently"
> aExtType := descriptorClass forceTypeNamed: aToken value
> ]
So what is cool about it? Generally, I find the above pattern *very*
hard to read and understand. There is a non-local return in the block,
xType is assigned to inconsistently (both inside the block and as the
result of evaluating the block), control-flow is mixed with data-flow,
all of which make the code harder to read and interpret. And when you
start extending the #ifAbsent: block and the first line moves outside
your visual field, it is *very* easy to forget that the result of that
block is potentially assigned to the variable.
To illustrate, here is a little quiz for you: What are the possible
results for xType after evaluating the following expression? [*]
xType := descriptorClass atomicTypeNamed: here ifAbsent:[
(Symbol hasInterned: here ifTrue:[
xType := #foo.
]) ifFalse:[
xType := #bar.
].
].
I think the result is very confusing and non-obvious so I'd rather see:
xType := descriptorClass atomicTypeNamed: here ifAbsent:[nil].
xType ifNil:[
(Symbol hasInterned: here ifTrue:[
xType := #foo.
]) ifFalse:[
xType := #bar.
].
].
This may be "uncool" but it sure as hell is also less surprising and
more predictable. Generally, my rule of thumb is: If you have a single
expression, like in
count := dict at: key ifAbsent:[self defaultCount].
then it's fine to use it in that way. If you have a complex sequence of
actions I prefer a style where I return a token and then take action
depending on that token, say
count := dict at: key ifAbsent:[token].
count == token ifTrue:[
"... go compute count ..."
].
This avoids the horrible mix of data and control flow by implicitly and
inconsistently assigning to a variable multiple levels up (which is the
root cause of the problem).
Cheers,
- Andreas
[*] The answer is nil and #bar. The code never results in #foo because
if that branch is taken the #ifAbsent: block actually evaluates to nil
and *that* value is being assigned to xType.
More information about the Squeak-dev
mailing list
|