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