Imagine, you have some object with amount and price variables.
And you want to calculate total, put this totals to collection and calculate grand total. Naive implementation will be something like total := amount * price for the first task and something like grandTotal := totals sum for the latter one. But what if amount or price are nil's? You can add nil checks, of course: total := (amount ifNil:[0]) * (price ifNil: [0]). And then what if totals will be empty? More checks. Is it really wise to have total to be zero if amount is nil? More ifTrue:ifFalse: code. And then you want to add amount := total / price calculation, and you realize that both total and price may be nil, and price may be zero. More and more and more checks. Protego (http://www.smalltalkhub.com/#!/~assargadon/Protego) adds "protected" versions of common operators and methods. So, you just put total := amount *@ price andgrandTotal := totals sum_protected into your code - and everything just works.total will be nil if any of the operands are nil. grandTotal will be calculated normally, even for empty totals collection (will return nil for empty collection). Collection can hold nil's and it will work anyway. If all elements of the collection is nil, result will be nil. Protected version of addition and subtraction will treat nil's as zeros until both operands are nil - then it will return nil. There are protected versions of comparisions, too. It's quite simple idea, which is still very useful, and it makes code much more readable, clean and self-commenting. That's why I have extracted this part of SmallPOS framework, and have published it as separate package to use it in other, non-SmallPOS applications. |
Hi Yuri,
Long time not seeing you ! welcome back :) Nice framework !
Esteban
|
In reply to this post by Yuriy Mironenko
Thanks for sharing. A similar thing might be useful for dealing with
"quality" of Process Variable measurement in industrial situations - where instruments fail from time to time. I'm not sure of all the pros and cons, but btw an alternative to hanging special behaviour on a method, would be to hang special behaviour on a MissingValue class that you could #initialize any instance variable to. Object subclass: #MissingValue instanceVariableNames: '' classVariableNames: '' package: 'AAAA' MissingValue >> * dummyValue self inform: 'debug trace - got here'. ^self MissingValue >> adaptToNumber: rcvr andSend: selector ^self perform: selector with: rcvr Collection >> sumProtected ^ self inject: 0 into: [ :sum :each | sum + each value] Usage... c := {1.1 * MissingValue new. 1.2 * 10. MissingValue new * 1.3. 10 * 1.4}. "==> an Array(aMissingValue 12.0 aMissingValue 14.0)" c sumExcludeMissing "==> 26.0" cheers -ben On Sun, Dec 18, 2016 at 6:45 PM, Юрий Мироненко <[hidden email]> wrote: > Imagine, you have some object with amount and price variables. > And you want to calculate total, put this totals to collection and calculate > grand total. > > Naive implementation will be something like > total := amount * price for the first task > and something like > grandTotal := totals sum for the latter one. > > But what if amount or price are nil's? > You can add nil checks, of course: total := (amount ifNil:[0]) * (price > ifNil: [0]). > And then what if totals will be empty? More checks. > Is it really wise to have total to be zero if amount is nil? More > ifTrue:ifFalse: code. > And then you want to add amount := total / price calculation, and you > realize that both total and price may be nil, and price may be zero. > More and more and more checks. > > Protego (http://www.smalltalkhub.com/#!/~assargadon/Protego) adds > "protected" versions of common operators and methods. > > So, you just put > total := amount *@ price > and > grandTotal := totals sum_protected > into your code - and everything just works. > > total will be nil if any of the operands are nil. grandTotal will be > calculated normally, even for empty totals collection (will return nil for > empty collection). > Collection can hold nil's and it will work anyway. If all elements of the > collection is nil, result will be nil. > > Protected version of addition and subtraction will treat nil's as zeros > until both operands are nil - then it will return nil. > There are protected versions of comparisions, too. > > It's quite simple idea, which is still very useful, and it makes code much > more readable, clean and self-commenting. > > That's why I have extracted this part of SmallPOS framework, and have > published it as separate package to use it in other, non-SmallPOS > applications. |
In reply to this post by Yuriy Mironenko
thanks for sharing it with us. Now in Moose we have metrics and when a metrics value is not available giving 0 is not the solution. We should probably have Value that wraps the real value for normal case and Unvalued for the case where there is no value. Stef On Sun, 18 Dec 2016 11:45:30 +0100, Юрий Мироненко <[hidden email]> wrote:
-- Using Opera's mail client: http://www.opera.com/mail/ |
In reply to this post by EstebanLM
Thank you, Esteban! You may believe me or not, but I dream about going to every ESUG conference every time.It's not framework this time, it's just small and simple package. And it makes life much, MUCH easier when developing business applications. 2016-12-18 15:39 GMT+03:00 Esteban Lorenzano <[hidden email]>:
|
In reply to this post by Ben Coman
Sorry, I'm not sure I fully understand your idea. What is the main difference between proposed MissingValue and UndefinedObject?It looks like trying to make another implementation of UndefinedObject, is it? 2016-12-18 18:12 GMT+03:00 Ben Coman <[hidden email]>: Thanks for sharing. A similar thing might be useful for dealing with |
2016-12-18 19:43 GMT+01:00 Юрий Мироненко <[hidden email]>:
MissingValue you will set up according to your business logic. While nil is just default value of variable which could be in your object by some incident, bug of application. |
2016-12-18 20:19 GMT+01:00 Denis Kudriashov <[hidden email]>:
And it makes impossible to distinguish bug from normal application state related to missing value |
In reply to this post by Yuriy Mironenko
On Mon, Dec 19, 2016 at 2:43 AM, Юрий Мироненко <[hidden email]> wrote:
> Sorry, I'm not sure I fully understand your idea. > It looks like trying to make another implementation of UndefinedObject, is > it? Just that. But it contains only business logic. I'm inclined to say both are the Null Object Pattern, but I'm not sure if concept truly applies to the system nil. https://www.tutorialspoint.com/design_pattern/null_object_pattern.htm https://www.cs.oberlin.edu/~jwalker/nullObjPattern/ > > What is the main difference between proposed MissingValue and > UndefinedObject? > It's just UndefinedObject is "too system" to intervene? Or something else? It could be nil for many reasons. Perhaps an initialization was missed. Mainly MissingValue avoids cluttering nil with custom logic. When looking via the Inspector or Debugger, a MissingValue provides a better indication of the status than a regular nil. Now you may want to avoid creating a new instance for each missing value. Perhaps the methods could have been added to the class side of MissingValue. Or use a singleton instance in the initialization. But I'm not sure of the pros/cons of each approach. Now I'm not saying MissingValue is the best way to go. Smalltalk does have the advantage of being able to add behaviour to nil and that might be sufficient for you. Just providing an additional way to think about it. cheers -ben > > > 2016-12-18 18:12 GMT+03:00 Ben Coman <[hidden email]>: >> >> Thanks for sharing. A similar thing might be useful for dealing with >> "quality" of Process Variable measurement in industrial situations - >> where instruments fail from time to time. >> >> I'm not sure of all the pros and cons, but btw an alternative to >> hanging special behaviour on a method, would be to hang special >> behaviour on a MissingValue class that you could #initialize any >> instance variable to. >> >> Object subclass: #MissingValue >> instanceVariableNames: '' >> classVariableNames: '' >> package: 'AAAA' >> >> MissingValue >> * dummyValue >> self inform: 'debug trace - got here'. >> ^self >> >> MissingValue >> adaptToNumber: rcvr andSend: selector >> ^self perform: selector with: rcvr >> >> Collection >> sumProtected >> ^ self >> inject: 0 >> into: [ :sum :each | sum + each value] >> >> Usage... >> >> c := {1.1 * MissingValue new. 1.2 * 10. MissingValue new * 1.3. 10 * >> 1.4}. >> "==> an Array(aMissingValue 12.0 aMissingValue 14.0)" >> >> c sumExcludeMissing >> "==> 26.0" >> >> cheers -ben >> >> On Sun, Dec 18, 2016 at 6:45 PM, Юрий Мироненко <[hidden email]> >> wrote: >> > Imagine, you have some object with amount and price variables. >> > And you want to calculate total, put this totals to collection and >> > calculate >> > grand total. >> > >> > Naive implementation will be something like >> > total := amount * price for the first task >> > and something like >> > grandTotal := totals sum for the latter one. >> > >> > But what if amount or price are nil's? >> > You can add nil checks, of course: total := (amount ifNil:[0]) * (price >> > ifNil: [0]). >> > And then what if totals will be empty? More checks. >> > Is it really wise to have total to be zero if amount is nil? More >> > ifTrue:ifFalse: code. >> > And then you want to add amount := total / price calculation, and you >> > realize that both total and price may be nil, and price may be zero. >> > More and more and more checks. >> > >> > Protego (http://www.smalltalkhub.com/#!/~assargadon/Protego) adds >> > "protected" versions of common operators and methods. >> > >> > So, you just put >> > total := amount *@ price >> > and >> > grandTotal := totals sum_protected >> > into your code - and everything just works. >> > >> > total will be nil if any of the operands are nil. grandTotal will be >> > calculated normally, even for empty totals collection (will return nil >> > for >> > empty collection). >> > Collection can hold nil's and it will work anyway. If all elements of >> > the >> > collection is nil, result will be nil. >> > >> > Protected version of addition and subtraction will treat nil's as zeros >> > until both operands are nil - then it will return nil. >> > There are protected versions of comparisions, too. >> > >> > It's quite simple idea, which is still very useful, and it makes code >> > much >> > more readable, clean and self-commenting. >> > >> > That's why I have extracted this part of SmallPOS framework, and have >> > published it as separate package to use it in other, non-SmallPOS >> > applications. >> > |
In reply to this post by Denis Kudriashov
Yes this is why it would be a good addition to protego On Sun, Dec 18, 2016 at 8:21 PM, Denis Kudriashov <[hidden email]> wrote:
|
Free forum by Nabble | Edit this page |