Hi guys
this afternoon we spent one hour with marcus looking at all the senders of at:ifPresent/ifAbsent: by looking at all the references to Smalltalk (far too much again but we will fix that soon).
It occurred to us that there is something strange because there are a lot of recurrent code.
It seems that: - first it would be better to let the compiler compiles method with reference to classes that are not in the system and let the system complain at execution tim (marcus suggestion and he can explain that much better than me). - second, it occurred to us that packages are missing in some cases because having a dependency mechanism (I'm not sure that it is the solution) would make sure that the code needing to be invoked is present in the image by the structural dependency between packages or registration where optional code can be declared
We would really appreciate to get you open a browser, look at the code (clean if you identify some dead code, ugly methods ;)) and share with us your impressions. And what are the solutions you see, because it seems to us that there are far too much use of this idiom.
Stef
Hi Stef -
It seems that:
- first it would be better to let the compiler compiles method with
reference to classes that are not in the system and let the system complain at execution tim (marcus suggestion and he can explain that much better than me).
I doubt this. Yes, all of these could be re-written as, say:
Foo ifNil:[self mumble]. Foo ifNotNil:[Foo bar].
instead of
Smalltalk at: #Foo ifAbsent:[self mumble] Smalltalk at: #Foo ifPresent:[:foo| foo bar].
but the main point is that the latter two are very verbose in conveying the intention that "yes, the caller is very well aware that Foo may be absent and that the dependency is a weak one". If you know how to read to the first one the same may be true but the latter is just simply obvious in this regard.
- second, it occurred to us that packages are missing in some cases
because having a dependency mechanism (I'm not sure that it is the solution) would make sure that the code needing to be invoked is present in the image by the structural dependency between packages or registration where optional code can be declared
I don't understand that. The whole point of using "Smalltalk at: #Foo ifAbsent:[]" is to declare a weak dependency, e.g., the presence of Foo may be advantageous but is by no means required. Of course, a dependency system could model these weak dependencies as well but only at the cost of clarity (see above).
We would really appreciate to get you open a browser, look at the code (clean if you identify some dead code, ugly methods ;)) and share with us your impressions. And what are the solutions you see, because it seems to us that there are far too much use of this idiom.
I'm not at all convinced that this is a bad idiom. The only problem I have with it is that it doesn't come up when you browse the references to a class (but that problem is easily fixable if someone just cares enough) and while you have made some points on how to "fix" the idiom you haven't made a very good (or bad ;-) argument why to fix it to begin with, e.g., why you'd think this idiom is problematic.
Cheers, - Andreas
Hi andreas
It seems that:
- first it would be better to let the compiler compiles method with
reference to classes that are not in the system and let the system complain at execution tim (marcus suggestion and he can explain that much better than me).
I doubt this. Yes, all of these could be re-written as, say:
Foo ifNil:[self mumble]. Foo ifNotNil:[Foo bar].
instead of
Smalltalk at: #Foo ifAbsent:[self mumble] Smalltalk at: #Foo ifPresent:[:foo| foo bar].
but the main point is that the latter two are very verbose in conveying the intention that "yes, the caller is very well aware that Foo may be absent and that the dependency is a weak one". If you know how to read to the first one the same may be true but the latter is just simply obvious in this regard.
I hope that marcus will explain what he thought :)
- second, it occurred to us that packages are missing in some cases
because having a dependency mechanism (I'm not sure that it is the solution) would make sure that the code needing to be invoked is present in the image by the structural dependency between packages or registration where optional code can be declared
I don't understand that. The whole point of using "Smalltalk at: #Foo ifAbsent:[]" is to declare a weak dependency, e.g., the presence of Foo may be advantageous but is by no means required. Of course, a dependency system could model these weak dependencies as well but only at the cost of clarity (see above).
I will try to explain better. If you know that you have package and that this the responsibility to package to make sure that when one reference another class in another package there is a dependency between package or that there is a configuration that make sure that your classes are loaded together. Then you as a class writer (vs. a "package plugger together") do not have to worry about that. In the smalltalk code we wrote we never get concerned with that since we know that one package in loaded in the context of certain configurations.
We would really appreciate to get you open a browser, look at the code (clean if you identify some dead code, ugly methods ;)) and share with us your impressions. And what are the solutions you see, because it seems to us that there are far too much use of this idiom.
I'm not at all convinced that this is a bad idiom. The only problem I have with it is that it doesn't come up when you browse the references to a class (but that problem is easily fixable if someone just cares enough) and while you have made some points on how to "fix" the idiom you haven't made a very good (or bad ;-) argument why to fix it to begin with, e.g., why you'd think this idiom is problematic.
Ok I will try to explain what we are thinking. but watch out this is fussy but I'm convinced there is something. I have the impression that you end up with a lot of ifdef kind of structure. and with a better package mechanism (right now we only have classes and not really package) we could separate these two aspects. Is it clearer?
Stef
Hi andreas
I'm mnore precise on my thoughts now after discussing mwith marcus and alex...I would like to identify what is class based responsibility vs. what is package-based responsibility. So in this quest I see severla cases:
1- you have a strong dependency between your classes: ie A to work need B and this could be solved by dependencies between package (PA will work only if PB will be in). So we can push to the package the responsibility and avoid ifPresent at the code level.
2- you want to express optionla behavior: for example if you look at clientEmail (I do not remember) but you can Smalltalk at: #MD5 ifPresent: [do Z]
what the code is doing is: in case of MD5 been present then do something extra else do not care.
Now this means that this is one way to express registration (a bit similar to the file list the file will do something only if certain tool are loaded and this is not the file list responsibility to say if this guys is in I will do that since it does not know which guy can be there).
In the context of the Smalltalk at:#MD5 ifPresent:... registration mechanism is overkill.
Then the next question is: is it the responsibility of the EmailClient to check whether MD5 is there or is it the responsibility of MD5 to say I'm here to potential client. I have the impression that this is a question of size.
The next question is if we have package do we want to move that at the package level vs class PackageRegistry if: #MD5 do: []. ?
I do not know but I would like to understand the architecture and properties that packages would bring to us.
Stef
Hi Stef -
It seems that:
- first it would be better to let the compiler compiles method with
reference to classes that are not in the system and let the system complain at execution tim (marcus suggestion and he can explain that much better than me).
I doubt this. Yes, all of these could be re-written as, say:
Foo ifNil:[self mumble]. Foo ifNotNil:[Foo bar].
instead of
Smalltalk at: #Foo ifAbsent:[self mumble] Smalltalk at: #Foo ifPresent:[:foo| foo bar].
but the main point is that the latter two are very verbose in conveying the intention that "yes, the caller is very well aware that Foo may be absent and that the dependency is a weak one". If you know how to read to the first one the same may be true but the latter is just simply obvious in this regard.
- second, it occurred to us that packages are missing in some cases
because having a dependency mechanism (I'm not sure that it is the solution) would make sure that the code needing to be invoked is present in the image by the structural dependency between packages or registration where optional code can be declared
I don't understand that. The whole point of using "Smalltalk at: #Foo ifAbsent:[]" is to declare a weak dependency, e.g., the presence of Foo may be advantageous but is by no means required. Of course, a dependency system could model these weak dependencies as well but only at the cost of clarity (see above).
We would really appreciate to get you open a browser, look at the code (clean if you identify some dead code, ugly methods ;)) and share with us your impressions. And what are the solutions you see, because it seems to us that there are far too much use of this idiom.
I'm not at all convinced that this is a bad idiom. The only problem I have with it is that it doesn't come up when you browse the references to a class (but that problem is easily fixable if someone just cares enough) and while you have made some points on how to "fix" the idiom you haven't made a very good (or bad ;-) argument why to fix it to begin with, e.g., why you'd think this idiom is problematic.
Cheers,
- Andreas
Hi Stef -
1- you have a strong dependency between your classes: ie A to work need B and this could be solved by dependencies between package (PA will work only if PB will be in). So we can push to the package the responsibility and avoid ifPresent at the code level.
Yes. I think that the idiom should not be used with strong dependencies (and I don't think I've ever seen it used in this case).
2- you want to express optionla behavior: for example if you look at clientEmail (I do not remember) but you can Smalltalk at: #MD5 ifPresent: [do Z]
what the code is doing is: in case of MD5 been present then do something extra else do not care.
Yes. Or alternatively choose different algorithms such as Form>>displayInterpolatedOn: which tries to use B3D for drawing and falls back onto WarpBlt if B3D is not present.
Now this means that this is one way to express registration (a bit similar to the file list the file will do something only if certain tool are loaded and this is not the file list responsibility to say if this guys is in I will do that since it does not know which guy can be there).
No. This is very different. In the FileList example, FileList does absolutely nothing by itself it is just a registry for a set of actions which need to be matched to files. Whereas here we have a very specific action to be performed, with the optional support of some other package.
Then the next question is: is it the responsibility of the EmailClient to check whether MD5 is there or is it the responsibility of MD5 to say I'm here to potential client.
It's both - and indeed this is precisely what happens. The MD5 package announces its presence by registering the classes in the environment (Smalltalk or otherwise) and the client checks if the MD5 is present and functioning.
The next question is if we have package do we want to move that at the package level vs class PackageRegistry if: #MD5 do: []. ?
This can be useful in situations where classes aren't the primary entry point but rather method interfaces. I think this would be a useful addition to the class-based tests.
Cheers, - Andreas
Andreas had this to say about testing for the presence of a class:
It seems that:
- first it would be better to let the compiler compiles method with
reference to classes that are not in the system and let the system complain at execution tim (marcus suggestion and he can explain that much better than me).
I doubt this. Yes, all of these could be re-written as, say:
Foo ifNil:[self mumble]. Foo ifNotNil:[Foo bar].
instead of
Smalltalk at: #Foo ifAbsent:[self mumble] Smalltalk at: #Foo ifPresent:[:foo| foo bar].
but the main point is that the latter two are very verbose in conveying the intention that "yes, the caller is very well aware that Foo may be absent and that the dependency is a weak one". If you know how to read to the first one the same may be true but the latter is just simply obvious in this regard.
You know, neither of these is really very satisfying. The first is ambiguous. There are any number of reasons why Foo could be nil, and a weak dependency is only one of them. My problem with the second one isn't so much the verbosity, it's that it also says "yes, the caller is well aware that class lookups go through a single global dictionary called Smalltalk." That is, it knows too much about the implementation of the compiler and runtime.
I think it would be nice to have something like this:
Foo ifPresent: [:foo | foo bar] ifAbsent: [self mumble]
This idiom clearly says what it means, "the dependency is a weak one" without saying more than that.
Colin
You know, neither of these is really very satisfying. The first is ambiguous. There are any number of reasons why Foo could be nil, and a weak dependency is only one of them. My problem with the second one isn't so much the verbosity, it's that it also says "yes, the caller is well aware that class lookups go through a single global dictionary called Smalltalk." That is, it knows too much about the implementation of the compiler and runtime.
I think it would be nice to have something like this:
Foo ifPresent: [:foo | foo bar]
ifAbsent: [self mumble]
This idiom clearly says what it means, "the dependency is a weak one" without saying more than that.
I like it but it's ambigious too if for any reason the value of Foo understands the message. The point is that the #ifPresent: message really is meta in the sense that it ought to be sent to the variable Foo instead of the value Foo.
Cheers, - Andreas
Andreas Raab wrote:
I like it but it's ambigious too if for any reason the value of Foo understands the message. The point is that the #ifPresent: message really is meta in the sense that it ought to be sent to the variable Foo instead of the value Foo.
Aren't you the one who keeps saying that Smalltalk doesn't have variables, just names that refer to objects? :-)
Given the limitation that we can't send a message to the variable (the binding, I guess) without changing the language, I still think this is a reasonable solution:
* it provides a consistent idiom for expressing a weak dependency * the default implementation can handle the class-loaded-or-absent case * other objects can override it to manage their own "presence."
That seems consistent with the way other parts of Smalltalk work, and it's a distinct improvement over the ad-hoc stuff we've all been doing.
Colin
Aren't you the one who keeps saying that Smalltalk doesn't have variables, just names that refer to objects? :-)
Err, no. I'm the guy who says fix the language! :-)
Heh, heh.
Cheers, - Andreas
----- Original Message ----- From: "Colin Putney" cputney@wiresong.ca To: "The general-purpose Squeak developers list" squeak-dev@lists.squeakfoundation.org Sent: Tuesday, November 30, 2004 2:50 PM Subject: Re: About Smalltalk at: .... ifAbsent:/present:
Andreas Raab wrote:
I like it but it's ambigious too if for any reason the value of Foo understands the message. The point is that the #ifPresent: message really is meta in the sense that it ought to be sent to the variable Foo instead of the value Foo.
Aren't you the one who keeps saying that Smalltalk doesn't have variables, just names that refer to objects? :-)
Given the limitation that we can't send a message to the variable (the binding, I guess) without changing the language, I still think this is a reasonable solution:
- it provides a consistent idiom for expressing a weak dependency
- the default implementation can handle the class-loaded-or-absent case
- other objects can override it to manage their own "presence."
That seems consistent with the way other parts of Smalltalk work, and it's a distinct improvement over the ad-hoc stuff we've all been doing.
Colin
"Andreas Raab" andreas.raab@gmx.de wrote:
Aren't you the one who keeps saying that Smalltalk doesn't have variables, just names that refer to objects? :-)
Err, no. I'm the guy who says fix the language! :-)
Heh, heh.
So given that - how do we fix it? Introduce a new way to refer to "globals", some kind of "binding" object?
Cheers,
- Andreas
regards, Göran
So given that - how do we fix it? Introduce a new way to refer to "globals", some kind of "binding" object?
The simplest way is probably to introduce a pseudo-operator like for example, "&" to refer to the binding object. For example:
&Foo isUndeclared "answers true if binding is undeclared" &Foo ifUndeclared:[...] "eval if binding is undeclared" &Foo ifAbsent:[...]. "eval if binding's value isn't present"
etc. with &Foo being a simple compiler hack which instead of emitting pushLiteralVariable bytecode (e.g., pushing the value of the binding) merely emits pushLiteralConstant (e.g., pushing the binding itself).
(note that in order to do this it would be extremely worthwhile to get away from using Associations and instead make some specific VariableBinding objects which implement the above methods)
Cheers, - Andreas
Hi!
"Andreas Raab" andreas.raab@gmx.de wrote:
So given that - how do we fix it? Introduce a new way to refer to "globals", some kind of "binding" object?
The simplest way is probably to introduce a pseudo-operator like for example, "&" to refer to the binding object. For example:
&Foo isUndeclared "answers true if binding is undeclared" &Foo ifUndeclared:[...] "eval if binding is undeclared" &Foo ifAbsent:[...]. "eval if binding's value isn't present"
etc. with &Foo being a simple compiler hack which instead of emitting pushLiteralVariable bytecode (e.g., pushing the value of the binding) merely emits pushLiteralConstant (e.g., pushing the binding itself).
Given my foray into Compiler land (Namespaces package) this doesn't seem hard to do at all. In fact, I get very tempted. :)
(note that in order to do this it would be extremely worthwhile to get away from using Associations and instead make some specific VariableBinding objects which implement the above methods)
Right.
Cheers,
- Andreas
Now... I don't really know what I am talking about - but is this in fact a special case of something bigger, something similar to hygienic macros or whatever it is called? (Slate, Scheme etc) I mean, some way of manipulating the AST of the code itself (which is my very shallow understanding of what that is)?
Just curious.
regards, Göran
Now... I don't really know what I am talking about - but is this in fact a special case of something bigger, something similar to hygienic macros or whatever it is called? (Slate, Scheme etc) I mean, some way of manipulating the AST of the code itself (which is my very shallow understanding of what that is)?
That is precisely right. It is easy to see how one would generalize the behavior to something like, e.g.,:
"Tell the variable var how to retrieve and store its value" &var toGet: [self instVarAt: 1] &var toSet: [:newValue| self instVarAt: 1 put: newValue].
Accessing variables is then conceptually equivalent to:
&var value. "read value of variable" &var value: newValue. "write value of variable"
With the compiler merely inlining the definitions of the accessors.
Cheers, - Andreas
OK, humor me on this, I'm trying to follow along.
In Smalltalk, as in most other OO languages, when you describe a class that requires another class, you do so with a specific, explicit reference:
myVar := SomeClass new.
Your object is now dependent on SomeClass. In compiled languages, this isn't a big deal because, hey, your code ain't gonna compile if SomeClass isn't available. (With some exceptions for dynamically loaded libraries, I suppose.)
But in Smalltalk, where formal parameters are untyped and the called code doesn't, in fact, care what's been passed to it as long as it can answer the right messages. Smalltalk doesn't do anything to check this until runtime, either.
So this sort of begs the question (to me) of why the class needs to be dependent. We could, of course, allow the client to set myVar rather than doing it in the code, but why couldn't SomeClass be defined as "any class that supports the interface I need to operate"? That would really be more Small-talky than what currently exists.
That might exacerbate the whole absent/present thing, dunno.
Count me in that group as well (since 1997). However, I don't think terribly much of these other experiments... Ideals are one thing; resulting designs and implementations, another.
On Nov 30, 2004, at 6:36 AM, Marcel Weiher wrote:
Seconded! :-) As a matter of fact, I am in the process of fixing it...sort of...
Marcel
On 30 Nov 2004, at 14:02, Andreas Raab wrote:
Err, no. I'm the guy who says fix the language! :-)
-- Brian T. Rice LOGOS Research and Development http://tunes.org/~water/
squeak-dev@lists.squeakfoundation.org