There are more knowledgeable people around here, but here is my take:
On Wed, Dec 26, 2012 at 4:32 PM, Sebastian Nozzi <[hidden email]> wrote: > Hello Smalltalkers, > > I was interacting the other day with an user in a Scala mailing list, > and he had some questions about Smalltalk. From his FP (functional > programming) point of view there were some things that looked strange. > I tried to reply to the best of my ability, but still I don't really > know the background for these design decisions. So I come to you, real > experts, hoping for some answers. > > The questions were: > > 1) Why do ST methods return "self" if nothing is explicitly returned? > (he would have expected something like "Unit" in Scala, or "Void" - > which I know makes little sense in a world like ST's, so I didn't > include this in the Stackoverflow question) > > http://stackoverflow.com/questions/14047887/why-do-methods-return-self-by-default-in-smalltalk >From the language design POV, it's certainly better than simply returning the value from the last expression in the method. If it returns the last value in the expression: the following method would return the result from #doSomething; but to know what kind of object would be returned from it, you need to recursively look into many methods. method1: var1 var1 doSomething. Why not return something along the line of nil is.... It certainly is more useful to be able to chain messages for simple setters. > 2) In Collections, why does "add:" return the object being added, and > not "self"? > > http://stackoverflow.com/questions/14047940/why-does-add-return-the-object-added-in-smalltalk-collections Smalltalk-72's "vector" had that semantics more or less, when assigning a new value to a slot. Check out "to vector" in http://ftp.squeak.org/goodies/Smalltalk-72/ALLDEFS I can see some reason for that semantics: One perhaps was that because assignment was just a message send to a quoted variable, and you can define its behavior based on the receiver. When the receiver is a quoted vector, your assignment can update a slot of it. In many languages (not in Scheme however), the value of the assignment is the value to be assigned so you can say: x := y := 0. So, it is convenient to make the value of such message to be the value to be assigned. Another is that it certainly is convenient to get back the removed element when you are removing an element from a collection. Making add: do the same makes it more symmetric. -- -- Yoshiki |
On Sun, Dec 30, 2012 at 7:40 AM, Bert Freudenberg <[hidden email]> wrote:
> On 2012-12-27, at 01:32, Sebastian Nozzi <[hidden email]> wrote: > >> Why do ST methods return "self" if nothing is explicitly returned? > > > One very simple reason has not been stated yet: In the Virtual Machine, returning self is simpler and more efficient than returning any other object. > > Smalltalk byte codes implement a stack machine. That means arguments are passed by pushing them onto a stack, rather than putting them into registers. In addition to the arguments as listed in the method signature, a hidden argument is always passed, which is the receiver of the message. So even for unary methods (those without arguments) the receiver is pushed onto the stack, then the method is executed, and the receiver value on the stack is how the method knows "self". By returning "self" if no explicit return statement is given, the VM can just leave the "self" oop on the stack, which saves at least one memory store operation. So from an efficiency and simplicity standpoint, returning "self" is the most elegant thing to do. I thought of it (when I wrote the reply) but isn't this really the argument for returning self instead of nil for example? Any message send pops all arguments including the receiver and pushes the return value so "self" is not on the stack. Typical byte code sequence for a method that returns self is popping the last result and ends the sequence with "returnSelf"; so it should be equally efficient if such a method endsWIth "returnNil", if such bytecode exists? -- -- Yoshiki |
In reply to this post by Yoshiki Ohshima-3
>> 2) In Collections, why does "add:" return the object being added, and
>> not "self"? >> >> http://stackoverflow.com/questions/14047940/why-does-add-return-the-object-added-in-smalltalk-collections > > Smalltalk-72's "vector" had that semantics more or less, when > assigning a new value to a slot. Check out "to vector" in > http://ftp.squeak.org/goodies/Smalltalk-72/ALLDEFS > > I can see some reason for that semantics: > > One perhaps was that because assignment was just a message send to a > quoted variable, and you can define its behavior based on the > receiver. When the receiver is a quoted vector, your assignment can > update a slot of it. In many languages (not in Scheme however), the > value of the assignment is the value to be assigned so you can say: > > x := y := 0. > > So, it is convenient to make the value of such message to be the value > to be assigned. > > Another is that it certainly is convenient to get back the removed > element when you are removing an element from a collection. Making > add: do the same makes it more symmetric. Those are my thoughts about that exactly! Nice to see someone else appreciate add:/remove: answering the argument besides myself. :) |
In reply to this post by Yoshiki Ohshima-3
Worth pointing out (at least I *think*) there's little real value in returning nil by default, even though it makes a certain amount of visceral sense.
Why would I return nil? Maybe as a sentinel value for something (often I prefer nil to zero for that when there's a nil concept and I want a sentinel.) Likewise, there's an argument for returning the last value of a method (like we do with blocks presently, and Self does everywhere) across the board, like e.g. Ruby does, but I'd note: Smalltalk's semantics had a lot of time to evolve. The advantages to answering self by default have stood the test of time in this context, I think:) though that certainly doesn't mean we shouldn't continue to ask questions and look for a better idea. On Dec 30, 2012, at 11:39 AM, Yoshiki Ohshima <[hidden email]> wrote: > On Sun, Dec 30, 2012 at 7:40 AM, Bert Freudenberg <[hidden email]> wrote: >> On 2012-12-27, at 01:32, Sebastian Nozzi <[hidden email]> wrote: >> >>> Why do ST methods return "self" if nothing is explicitly returned? >> >> >> One very simple reason has not been stated yet: In the Virtual Machine, returning self is simpler and more efficient than returning any other object. >> >> Smalltalk byte codes implement a stack machine. That means arguments are passed by pushing them onto a stack, rather than putting them into registers. In addition to the arguments as listed in the method signature, a hidden argument is always passed, which is the receiver of the message. So even for unary methods (those without arguments) the receiver is pushed onto the stack, then the method is executed, and the receiver value on the stack is how the method knows "self". By returning "self" if no explicit return statement is given, the VM can just leave the "self" oop on the stack, which saves at least one memory store operation. So from an efficiency and simplicity standpoint, returning "self" is the most elegant thing to do. > > I thought of it (when I wrote the reply) but isn't this really the > argument for returning self instead of nil for example? Any message > send pops all arguments including the receiver and pushes the return > value so "self" is not on the stack. Typical byte code sequence for a > method that returns self is popping the last result and ends the > sequence with "returnSelf"; so it should be equally efficient if such > a method endsWIth "returnNil", if such bytecode exists? > > -- > -- Yoshiki > |
On 31 December 2012 05:13, Casey Ransberger <[hidden email]> wrote:
> Worth pointing out (at least I *think*) there's little real value in returning nil by default, even though it makes a certain amount of visceral sense. > > Why would I return nil? Maybe as a sentinel value for something (often I prefer nil to zero for that when there's a nil concept and I want a sentinel.) The problem with nil as a sentinel is that it's not sufficiently different from the other things in one's collection. I recall the troubles people had trying to store nils in a Set (which used nil for some special purpose). But there's a trivial way to get a really true blue unique sentinel: sentinel := Object new. > Likewise, there's an argument for returning the last value of a method (like we do with blocks presently, and Self does everywhere) across the board, like e.g. Ruby does, but I'd note: Smalltalk's semantics had a lot of time to evolve. The advantages to answering self by default have stood the test of time in this context, I think:) though that certainly doesn't mean we shouldn't continue to ask questions and look for a better idea. Certainly, if you didn't return self by default you'd lose the trivial cascading. (Look at the hoops others have to jump through to get their "fluent" APIs.) Given my particular interest in the intersection between the techniques of functional and OO programming I rarely use "return self by default". I instead get tripped up by forgetting to use a ^ on the last statement. But I'm not going to suggest we change the return-self behaviour :) frank > On Dec 30, 2012, at 11:39 AM, Yoshiki Ohshima <[hidden email]> wrote: > >> On Sun, Dec 30, 2012 at 7:40 AM, Bert Freudenberg <[hidden email]> wrote: >>> On 2012-12-27, at 01:32, Sebastian Nozzi <[hidden email]> wrote: >>> >>>> Why do ST methods return "self" if nothing is explicitly returned? >>> >>> >>> One very simple reason has not been stated yet: In the Virtual Machine, returning self is simpler and more efficient than returning any other object. >>> >>> Smalltalk byte codes implement a stack machine. That means arguments are passed by pushing them onto a stack, rather than putting them into registers. In addition to the arguments as listed in the method signature, a hidden argument is always passed, which is the receiver of the message. So even for unary methods (those without arguments) the receiver is pushed onto the stack, then the method is executed, and the receiver value on the stack is how the method knows "self". By returning "self" if no explicit return statement is given, the VM can just leave the "self" oop on the stack, which saves at least one memory store operation. So from an efficiency and simplicity standpoint, returning "self" is the most elegant thing to do. >> >> I thought of it (when I wrote the reply) but isn't this really the >> argument for returning self instead of nil for example? Any message >> send pops all arguments including the receiver and pushes the return >> value so "self" is not on the stack. Typical byte code sequence for a >> method that returns self is popping the last result and ends the >> sequence with "returnSelf"; so it should be equally efficient if such >> a method endsWIth "returnNil", if such bytecode exists? >> >> -- >> -- Yoshiki >> > |
2012/12/31 Frank Shearar <[hidden email]>:
> On 31 December 2012 05:13, Casey Ransberger <[hidden email]> wrote: >> Worth pointing out (at least I *think*) there's little real value in returning nil by default, even though it makes a certain amount of visceral sense. >> >> Why would I return nil? Maybe as a sentinel value for something (often I prefer nil to zero for that when there's a nil concept and I want a sentinel.) > > The problem with nil as a sentinel is that it's not sufficiently > different from the other things in one's collection. I recall the > troubles people had trying to store nils in a Set (which used nil for > some special purpose). But there's a trivial way to get a really true > blue unique sentinel: sentinel := Object new. > >> Likewise, there's an argument for returning the last value of a method (like we do with blocks presently, and Self does everywhere) across the board, like e.g. Ruby does, but I'd note: Smalltalk's semantics had a lot of time to evolve. The advantages to answering self by default have stood the test of time in this context, I think:) though that certainly doesn't mean we shouldn't continue to ask questions and look for a better idea. > > Certainly, if you didn't return self by default you'd lose the trivial > cascading. (Look at the hoops others have to jump through to get their > "fluent" APIs.) > > Given my particular interest in the intersection between the > techniques of functional and OO programming I rarely use "return self > by default". I instead get tripped up by forgetting to use a ^ on the > last statement. But I'm not going to suggest we change the return-self > behaviour :) > > frank > An argument for NOT returning the result of last statement is that it would more than often expose internal state of the object to the outside (in the case you sent last message to an instance variable). Nicolas >> On Dec 30, 2012, at 11:39 AM, Yoshiki Ohshima <[hidden email]> wrote: >> >>> On Sun, Dec 30, 2012 at 7:40 AM, Bert Freudenberg <[hidden email]> wrote: >>>> On 2012-12-27, at 01:32, Sebastian Nozzi <[hidden email]> wrote: >>>> >>>>> Why do ST methods return "self" if nothing is explicitly returned? >>>> >>>> >>>> One very simple reason has not been stated yet: In the Virtual Machine, returning self is simpler and more efficient than returning any other object. >>>> >>>> Smalltalk byte codes implement a stack machine. That means arguments are passed by pushing them onto a stack, rather than putting them into registers. In addition to the arguments as listed in the method signature, a hidden argument is always passed, which is the receiver of the message. So even for unary methods (those without arguments) the receiver is pushed onto the stack, then the method is executed, and the receiver value on the stack is how the method knows "self". By returning "self" if no explicit return statement is given, the VM can just leave the "self" oop on the stack, which saves at least one memory store operation. So from an efficiency and simplicity standpoint, returning "self" is the most elegant thing to do. >>> >>> I thought of it (when I wrote the reply) but isn't this really the >>> argument for returning self instead of nil for example? Any message >>> send pops all arguments including the receiver and pushes the return >>> value so "self" is not on the stack. Typical byte code sequence for a >>> method that returns self is popping the last result and ends the >>> sequence with "returnSelf"; so it should be equally efficient if such >>> a method endsWIth "returnNil", if such bytecode exists? >>> >>> -- >>> -- Yoshiki >>> >> > |
2012/12/31 Nicolas Cellier <[hidden email]>:
> 2012/12/31 Frank Shearar <[hidden email]>: >> On 31 December 2012 05:13, Casey Ransberger <[hidden email]> wrote: >>> Worth pointing out (at least I *think*) there's little real value in returning nil by default, even though it makes a certain amount of visceral sense. >>> >>> Why would I return nil? Maybe as a sentinel value for something (often I prefer nil to zero for that when there's a nil concept and I want a sentinel.) >> >> The problem with nil as a sentinel is that it's not sufficiently >> different from the other things in one's collection. I recall the >> troubles people had trying to store nils in a Set (which used nil for >> some special purpose). But there's a trivial way to get a really true >> blue unique sentinel: sentinel := Object new. >> >>> Likewise, there's an argument for returning the last value of a method (like we do with blocks presently, and Self does everywhere) across the board, like e.g. Ruby does, but I'd note: Smalltalk's semantics had a lot of time to evolve. The advantages to answering self by default have stood the test of time in this context, I think:) though that certainly doesn't mean we shouldn't continue to ask questions and look for a better idea. >> >> Certainly, if you didn't return self by default you'd lose the trivial >> cascading. (Look at the hoops others have to jump through to get their >> "fluent" APIs.) >> >> Given my particular interest in the intersection between the >> techniques of functional and OO programming I rarely use "return self >> by default". I instead get tripped up by forgetting to use a ^ on the >> last statement. But I'm not going to suggest we change the return-self >> behaviour :) >> >> frank >> > > An argument for NOT returning the result of last statement is that it > would more than often expose internal state of the object to the > outside (in the case you sent last message to an instance variable). > > Nicolas > Or, from an other point of view, that means that Smalltalk is more imperative tan functional... Nicolas >>> On Dec 30, 2012, at 11:39 AM, Yoshiki Ohshima <[hidden email]> wrote: >>> >>>> On Sun, Dec 30, 2012 at 7:40 AM, Bert Freudenberg <[hidden email]> wrote: >>>>> On 2012-12-27, at 01:32, Sebastian Nozzi <[hidden email]> wrote: >>>>> >>>>>> Why do ST methods return "self" if nothing is explicitly returned? >>>>> >>>>> >>>>> One very simple reason has not been stated yet: In the Virtual Machine, returning self is simpler and more efficient than returning any other object. >>>>> >>>>> Smalltalk byte codes implement a stack machine. That means arguments are passed by pushing them onto a stack, rather than putting them into registers. In addition to the arguments as listed in the method signature, a hidden argument is always passed, which is the receiver of the message. So even for unary methods (those without arguments) the receiver is pushed onto the stack, then the method is executed, and the receiver value on the stack is how the method knows "self". By returning "self" if no explicit return statement is given, the VM can just leave the "self" oop on the stack, which saves at least one memory store operation. So from an efficiency and simplicity standpoint, returning "self" is the most elegant thing to do. >>>> >>>> I thought of it (when I wrote the reply) but isn't this really the >>>> argument for returning self instead of nil for example? Any message >>>> send pops all arguments including the receiver and pushes the return >>>> value so "self" is not on the stack. Typical byte code sequence for a >>>> method that returns self is popping the last result and ends the >>>> sequence with "returnSelf"; so it should be equally efficient if such >>>> a method endsWIth "returnNil", if such bytecode exists? >>>> >>>> -- >>>> -- Yoshiki >>>> >>> >> |
On 31 December 2012 10:04, Nicolas Cellier
<[hidden email]> wrote: > 2012/12/31 Nicolas Cellier <[hidden email]>: >> 2012/12/31 Frank Shearar <[hidden email]>: >>> On 31 December 2012 05:13, Casey Ransberger <[hidden email]> wrote: >>>> Worth pointing out (at least I *think*) there's little real value in returning nil by default, even though it makes a certain amount of visceral sense. >>>> >>>> Why would I return nil? Maybe as a sentinel value for something (often I prefer nil to zero for that when there's a nil concept and I want a sentinel.) >>> >>> The problem with nil as a sentinel is that it's not sufficiently >>> different from the other things in one's collection. I recall the >>> troubles people had trying to store nils in a Set (which used nil for >>> some special purpose). But there's a trivial way to get a really true >>> blue unique sentinel: sentinel := Object new. >>> >>>> Likewise, there's an argument for returning the last value of a method (like we do with blocks presently, and Self does everywhere) across the board, like e.g. Ruby does, but I'd note: Smalltalk's semantics had a lot of time to evolve. The advantages to answering self by default have stood the test of time in this context, I think:) though that certainly doesn't mean we shouldn't continue to ask questions and look for a better idea. >>> >>> Certainly, if you didn't return self by default you'd lose the trivial >>> cascading. (Look at the hoops others have to jump through to get their >>> "fluent" APIs.) >>> >>> Given my particular interest in the intersection between the >>> techniques of functional and OO programming I rarely use "return self >>> by default". I instead get tripped up by forgetting to use a ^ on the >>> last statement. But I'm not going to suggest we change the return-self >>> behaviour :) >>> >>> frank >>> >> >> An argument for NOT returning the result of last statement is that it >> would more than often expose internal state of the object to the >> outside (in the case you sent last message to an instance variable). >> >> Nicolas >> > > Or, from an other point of view, that means that Smalltalk is more > imperative tan functional... Well, I don't know about that. Certainly many of the standard APIs are imperative (like remove: returning the deleted element rather than a new collection with the element removed). But for instance, how about "there's no distinction between a statement and an expression", which is a pretty Functional (tm) feature. frank > Nicolas > >>>> On Dec 30, 2012, at 11:39 AM, Yoshiki Ohshima <[hidden email]> wrote: >>>> >>>>> On Sun, Dec 30, 2012 at 7:40 AM, Bert Freudenberg <[hidden email]> wrote: >>>>>> On 2012-12-27, at 01:32, Sebastian Nozzi <[hidden email]> wrote: >>>>>> >>>>>>> Why do ST methods return "self" if nothing is explicitly returned? >>>>>> >>>>>> >>>>>> One very simple reason has not been stated yet: In the Virtual Machine, returning self is simpler and more efficient than returning any other object. >>>>>> >>>>>> Smalltalk byte codes implement a stack machine. That means arguments are passed by pushing them onto a stack, rather than putting them into registers. In addition to the arguments as listed in the method signature, a hidden argument is always passed, which is the receiver of the message. So even for unary methods (those without arguments) the receiver is pushed onto the stack, then the method is executed, and the receiver value on the stack is how the method knows "self". By returning "self" if no explicit return statement is given, the VM can just leave the "self" oop on the stack, which saves at least one memory store operation. So from an efficiency and simplicity standpoint, returning "self" is the most elegant thing to do. >>>>> >>>>> I thought of it (when I wrote the reply) but isn't this really the >>>>> argument for returning self instead of nil for example? Any message >>>>> send pops all arguments including the receiver and pushes the return >>>>> value so "self" is not on the stack. Typical byte code sequence for a >>>>> method that returns self is popping the last result and ends the >>>>> sequence with "returnSelf"; so it should be equally efficient if such >>>>> a method endsWIth "returnNil", if such bytecode exists? >>>>> >>>>> -- >>>>> -- Yoshiki >>>>> >>>> >>> > |
2012/12/31 Frank Shearar <[hidden email]>:
> On 31 December 2012 10:04, Nicolas Cellier > <[hidden email]> wrote: >> 2012/12/31 Nicolas Cellier <[hidden email]>: >>> 2012/12/31 Frank Shearar <[hidden email]>: >>>> On 31 December 2012 05:13, Casey Ransberger <[hidden email]> wrote: >>>>> Worth pointing out (at least I *think*) there's little real value in returning nil by default, even though it makes a certain amount of visceral sense. >>>>> >>>>> Why would I return nil? Maybe as a sentinel value for something (often I prefer nil to zero for that when there's a nil concept and I want a sentinel.) >>>> >>>> The problem with nil as a sentinel is that it's not sufficiently >>>> different from the other things in one's collection. I recall the >>>> troubles people had trying to store nils in a Set (which used nil for >>>> some special purpose). But there's a trivial way to get a really true >>>> blue unique sentinel: sentinel := Object new. >>>> >>>>> Likewise, there's an argument for returning the last value of a method (like we do with blocks presently, and Self does everywhere) across the board, like e.g. Ruby does, but I'd note: Smalltalk's semantics had a lot of time to evolve. The advantages to answering self by default have stood the test of time in this context, I think:) though that certainly doesn't mean we shouldn't continue to ask questions and look for a better idea. >>>> >>>> Certainly, if you didn't return self by default you'd lose the trivial >>>> cascading. (Look at the hoops others have to jump through to get their >>>> "fluent" APIs.) >>>> >>>> Given my particular interest in the intersection between the >>>> techniques of functional and OO programming I rarely use "return self >>>> by default". I instead get tripped up by forgetting to use a ^ on the >>>> last statement. But I'm not going to suggest we change the return-self >>>> behaviour :) >>>> >>>> frank >>>> >>> >>> An argument for NOT returning the result of last statement is that it >>> would more than often expose internal state of the object to the >>> outside (in the case you sent last message to an instance variable). >>> >>> Nicolas >>> >> >> Or, from an other point of view, that means that Smalltalk is more >> imperative tan functional... > > Well, I don't know about that. Certainly many of the standard APIs are > imperative (like remove: returning the deleted element rather than a > new collection with the element removed). But for instance, how about > "there's no distinction between a statement and an expression", which > is a pretty Functional (tm) feature. > > frank > Certainly, one of imperative language with most functional features... I played with these snippets: (SystemNavigation default allMethodsSelect: [:e | | scanner | scanner := InstructionStream on: e. scanner scanFor: [:byte | byte = 120]]) size. -> 21944 (SystemNavigation default allMethodsSelect: [:e | | scanner | scanner := InstructionStream on: e. scanner scanFor: [:byte | (byte between: 121 and: 124)]]) size. -> 23668 Byte code 120 does return the receiver, 121 true, 12 false, 123 nil, 124 stack top, 125 is for block local return. So above snippets means that roughly 50% of methods return the receiver (self). The snippet is not perfect, because some methods return both self and another object (SystemNavigation default allMethodsSelect: [:e | | scanner | scanner := InstructionStream on: e. (scanner scanFor: [:byte | (byte between: 121 and: 124)]) and: [scanner scanFor: [:byte | byte = 120]]]) size. -> 1478 Also, it does not cover all methods (SystemNavigation default allMethodsSelect: [:e | true]) size. -> 47547 The 3627 simple method that just return an Object (a literal or an instance variable) were not caught by the InstructionStream SystemNavigation default browseAllSelect: [:e | | scanner | scanner := InstructionStream on: e. (scanner scanFor: [:byte | (byte between: 120 and: 124)]) not]. Nicolas >> Nicolas >> >>>>> On Dec 30, 2012, at 11:39 AM, Yoshiki Ohshima <[hidden email]> wrote: >>>>> >>>>>> On Sun, Dec 30, 2012 at 7:40 AM, Bert Freudenberg <[hidden email]> wrote: >>>>>>> On 2012-12-27, at 01:32, Sebastian Nozzi <[hidden email]> wrote: >>>>>>> >>>>>>>> Why do ST methods return "self" if nothing is explicitly returned? >>>>>>> >>>>>>> >>>>>>> One very simple reason has not been stated yet: In the Virtual Machine, returning self is simpler and more efficient than returning any other object. >>>>>>> >>>>>>> Smalltalk byte codes implement a stack machine. That means arguments are passed by pushing them onto a stack, rather than putting them into registers. In addition to the arguments as listed in the method signature, a hidden argument is always passed, which is the receiver of the message. So even for unary methods (those without arguments) the receiver is pushed onto the stack, then the method is executed, and the receiver value on the stack is how the method knows "self". By returning "self" if no explicit return statement is given, the VM can just leave the "self" oop on the stack, which saves at least one memory store operation. So from an efficiency and simplicity standpoint, returning "self" is the most elegant thing to do. >>>>>> >>>>>> I thought of it (when I wrote the reply) but isn't this really the >>>>>> argument for returning self instead of nil for example? Any message >>>>>> send pops all arguments including the receiver and pushes the return >>>>>> value so "self" is not on the stack. Typical byte code sequence for a >>>>>> method that returns self is popping the last result and ends the >>>>>> sequence with "returnSelf"; so it should be equally efficient if such >>>>>> a method endsWIth "returnNil", if such bytecode exists? >>>>>> >>>>>> -- >>>>>> -- Yoshiki >>>>>> >>>>> >>>> >> > |
Thank you, Nicolas, for these instructive code snippets and Happy New Year 2013
--Hannes On 12/31/12, Nicolas Cellier <[hidden email]> wrote: > 2012/12/31 Frank Shearar <[hidden email]>: >> On 31 December 2012 10:04, Nicolas Cellier >> <[hidden email]> wrote: >>> 2012/12/31 Nicolas Cellier <[hidden email]>: >>>> 2012/12/31 Frank Shearar <[hidden email]>: >>>>> On 31 December 2012 05:13, Casey Ransberger <[hidden email]> >>>>> wrote: >>>>>> Worth pointing out (at least I *think*) there's little real value in >>>>>> returning nil by default, even though it makes a certain amount of >>>>>> visceral sense. >>>>>> >>>>>> Why would I return nil? Maybe as a sentinel value for something (often >>>>>> I prefer nil to zero for that when there's a nil concept and I want a >>>>>> sentinel.) >>>>> >>>>> The problem with nil as a sentinel is that it's not sufficiently >>>>> different from the other things in one's collection. I recall the >>>>> troubles people had trying to store nils in a Set (which used nil for >>>>> some special purpose). But there's a trivial way to get a really true >>>>> blue unique sentinel: sentinel := Object new. >>>>> >>>>>> Likewise, there's an argument for returning the last value of a method >>>>>> (like we do with blocks presently, and Self does everywhere) across >>>>>> the board, like e.g. Ruby does, but I'd note: Smalltalk's semantics >>>>>> had a lot of time to evolve. The advantages to answering self by >>>>>> default have stood the test of time in this context, I think:) though >>>>>> that certainly doesn't mean we shouldn't continue to ask questions and >>>>>> look for a better idea. >>>>> >>>>> Certainly, if you didn't return self by default you'd lose the trivial >>>>> cascading. (Look at the hoops others have to jump through to get their >>>>> "fluent" APIs.) >>>>> >>>>> Given my particular interest in the intersection between the >>>>> techniques of functional and OO programming I rarely use "return self >>>>> by default". I instead get tripped up by forgetting to use a ^ on the >>>>> last statement. But I'm not going to suggest we change the return-self >>>>> behaviour :) >>>>> >>>>> frank >>>>> >>>> >>>> An argument for NOT returning the result of last statement is that it >>>> would more than often expose internal state of the object to the >>>> outside (in the case you sent last message to an instance variable). >>>> >>>> Nicolas >>>> >>> >>> Or, from an other point of view, that means that Smalltalk is more >>> imperative tan functional... >> >> Well, I don't know about that. Certainly many of the standard APIs are >> imperative (like remove: returning the deleted element rather than a >> new collection with the element removed). But for instance, how about >> "there's no distinction between a statement and an expression", which >> is a pretty Functional (tm) feature. >> >> frank >> > > Certainly, one of imperative language with most functional features... > I played with these snippets: > > (SystemNavigation default allMethodsSelect: [:e | > | scanner | > scanner := InstructionStream on: e. > scanner scanFor: [:byte | byte = 120]]) size. > -> 21944 > > (SystemNavigation default allMethodsSelect: [:e | > | scanner | > scanner := InstructionStream on: e. > scanner scanFor: [:byte | (byte between: 121 and: 124)]]) size. > -> 23668 > > Byte code 120 does return the receiver, 121 true, 12 false, 123 nil, > 124 stack top, 125 is for block local return. > So above snippets means that roughly 50% of methods return the receiver > (self). > > The snippet is not perfect, because some methods return both self and > another object > (SystemNavigation default allMethodsSelect: [:e | > | scanner | > scanner := InstructionStream on: e. > (scanner scanFor: [:byte | (byte between: 121 and: 124)]) > and: [scanner scanFor: [:byte | byte = 120]]]) size. > -> 1478 > > Also, it does not cover all methods > (SystemNavigation default allMethodsSelect: [:e | true]) size. > -> 47547 > > The 3627 simple method that just return an Object (a literal or an > instance variable) were not caught by the InstructionStream > SystemNavigation default browseAllSelect: [:e | > | scanner | > scanner := InstructionStream on: e. > (scanner scanFor: [:byte | (byte between: 120 and: 124)]) not]. > > Nicolas > >>> Nicolas >>> >>>>>> On Dec 30, 2012, at 11:39 AM, Yoshiki Ohshima >>>>>> <[hidden email]> wrote: >>>>>> >>>>>>> On Sun, Dec 30, 2012 at 7:40 AM, Bert Freudenberg >>>>>>> <[hidden email]> wrote: >>>>>>>> On 2012-12-27, at 01:32, Sebastian Nozzi <[hidden email]> >>>>>>>> wrote: >>>>>>>> >>>>>>>>> Why do ST methods return "self" if nothing is explicitly returned? >>>>>>>> >>>>>>>> >>>>>>>> One very simple reason has not been stated yet: In the Virtual >>>>>>>> Machine, returning self is simpler and more efficient than returning >>>>>>>> any other object. >>>>>>>> >>>>>>>> Smalltalk byte codes implement a stack machine. That means arguments >>>>>>>> are passed by pushing them onto a stack, rather than putting them >>>>>>>> into registers. In addition to the arguments as listed in the method >>>>>>>> signature, a hidden argument is always passed, which is the receiver >>>>>>>> of the message. So even for unary methods (those without arguments) >>>>>>>> the receiver is pushed onto the stack, then the method is executed, >>>>>>>> and the receiver value on the stack is how the method knows "self". >>>>>>>> By returning "self" if no explicit return statement is given, the VM >>>>>>>> can just leave the "self" oop on the stack, which saves at least one >>>>>>>> memory store operation. So from an efficiency and simplicity >>>>>>>> standpoint, returning "self" is the most elegant thing to do. >>>>>>> >>>>>>> I thought of it (when I wrote the reply) but isn't this really the >>>>>>> argument for returning self instead of nil for example? Any message >>>>>>> send pops all arguments including the receiver and pushes the return >>>>>>> value so "self" is not on the stack. Typical byte code sequence for >>>>>>> a >>>>>>> method that returns self is popping the last result and ends the >>>>>>> sequence with "returnSelf"; so it should be equally efficient if >>>>>>> such >>>>>>> a method endsWIth "returnNil", if such bytecode exists? >>>>>>> >>>>>>> -- >>>>>>> -- Yoshiki >>>>>>> >>>>>> >>>>> >>> >> > > |
In reply to this post by Casey Ransberger-2
On Sun, Dec 30, 2012 at 9:13 PM, Casey Ransberger <[hidden email]> wrote: Worth pointing out (at least I *think*) there's little real value in returning nil by default, even though it makes a certain amount of visceral sense. turns out in a distributed systems context nil is far cheaper to return; no minting of a proxy for the result. That's a specialized use. But answering nil when there's no result has a safety aspect, i that it guards somewhat against using the return value when its not intended (nil has some protocol).
best, Eliot
|
On 3 January 2013 03:56, Eliot Miranda <[hidden email]> wrote:
> > > > On Sun, Dec 30, 2012 at 9:13 PM, Casey Ransberger <[hidden email]> > wrote: >> >> Worth pointing out (at least I *think*) there's little real value in >> returning nil by default, even though it makes a certain amount of visceral >> sense. > > > turns out in a distributed systems context nil is far cheaper to return; no > minting of a proxy for the result. That's a specialized use. But answering > nil when there's no result has a safety aspect, i that it guards somewhat > against using the return value when its not intended (nil has some > protocol). > I was also thinking that way before i found that in distributed systems nil is no longer a singleton: - suppose i extended Object class with some method, lets say #foo. - then my user code sends some remote message to some arbitrary object in a system with such extension, which evaluates answer to nil - and then i sending #foo message to result. now if you substitute remote nil with own nil, you will get DNU, because remote system nil can understand that message, but local is not. But in case of return self, this is actually works much better: the communication layer can check that message answer is same as a receiver (using identity check), and then, indeed, it can do a shortcut and tell the remote sender system that it can reuse the same proxy (which it used for sending a message) for further operations. -- Best regards, Igor Stasenko. |
In reply to this post by Casey Ransberger-2
There are two major reasons why returning nil by default makes sense: * It is consistent with what people see when looking at the code, i.e., if a method doesn't return anything visibly it shouldn't silently do something completely different. This makes the language easier to learn since there are fewer special cases to know about. * It prevents implicitly leaking authority. This of course is only relevant for people who care about security aspects but in this case returning self is really the wrong choice (so is evaluating the last statement of blocks to be the block return value; block return should be explicit too). Cheers, - Andreas |
In reply to this post by Igor Stasenko
But in general, the problem lies in delegation. As long as you return the receiver of the message the return is simple. But if the receiver delegates to another object along the lines of: doSomethingWithFoo: arg "Do something with my ivar foo and the argument" ^foo doSomethingWith: arg then the implicit return of self from foo will cause you to create excess proxies. Much better to return nil. You can still proxy nil as a "real object" if you really want to treat remote nil different from local nil (although I've never found a situation where this proved useful). One real-world example of how implicit returns negatively affect distributed systems, we found that in Croquet, the implicit return from blocks would create a ton of garbage promises that were never used. For example, if one were to write: foo ifNotNil:[foo future yourself]. this would create a (completely useless) promise for the future as it would be referred to as the result from the block. We changed this so that futures that were the last statement of a block return nil and do not create a promise (and nobody ever complained :-) Also, note that the problem would be compounded if the return would require a network round-trip too (in Croquet it doesn't); in this case you pay for the promise and for proxying an implicit self return from some completely uninteresting object that nobody will look at afterwards. The negative effects of implicit returns are definitely noticable in distributed systems when you're trying to utilize proxies efficiently. Knowing when (not) to create a proxy and when (not) to return an object is a major help in making the system efficient. Cheers, - Andreas |
In reply to this post by Andreas.Raab
Hi:
On 03 Jan 2013, at 13:37, Andreas.Raab wrote: > * It prevents implicitly leaking authority. This of course is only relevant > for people who care about security aspects but in this case returning self > is really the wrong choice (so is evaluating the last statement of blocks to > be the block return value; block return should be explicit too). Then you would need second kind of return operator to distinguish between value returns and non-local returns from methods, no? Just curious. Best regards Stefan -- Stefan Marr Software Languages Lab Vrije Universiteit Brussel Pleinlaan 2 / B-1050 Brussels / Belgium http://soft.vub.ac.be/~smarr Phone: +32 2 629 2974 Fax: +32 2 629 3525 |
Free forum by Nabble | Edit this page |