Protego - smart way to manage NIL's in business calculations

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Protego - smart way to manage NIL's in business calculations

Yuriy Mironenko
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.
Reply | Threaded
Open this post in threaded view
|

Re: Protego - smart way to manage NIL's in business calculations

EstebanLM
Hi Yuri, 

Long time not seeing you ! welcome back :)
Nice framework !

Esteban

On 18 Dec 2016, at 11:45, Юрий Мироненко <[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.

Reply | Threaded
Open this post in threaded view
|

Re: Protego - smart way to manage NIL's in business calculations

Ben Coman
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.

Reply | Threaded
Open this post in threaded view
|

Re: Protego - smart way to manage NIL's in business calculations

stepharong
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:

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.



--
Using Opera's mail client: http://www.opera.com/mail/
Reply | Threaded
Open this post in threaded view
|

Re: Protego - smart way to manage NIL's in business calculations

Yuriy Mironenko
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]>:
Hi Yuri, 

Long time not seeing you ! welcome back :)
Nice framework !

Esteban

On 18 Dec 2016, at 11:45, Юрий Мироненко <[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.


Reply | Threaded
Open this post in threaded view
|

Re: Protego - smart way to manage NIL's in business calculations

Yuriy Mironenko
In reply to this post by Ben Coman
Sorry, I'm not sure I fully understand your idea.
It looks like trying to make another implementation of UndefinedObject, is it?

What is the main difference between proposed MissingValue and UndefinedObject?
It's just UndefinedObject is "too system" to intervene? Or something else?


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.


Reply | Threaded
Open this post in threaded view
|

Re: Protego - smart way to manage NIL's in business calculations

Denis Kudriashov

2016-12-18 19:43 GMT+01:00 Юрий Мироненко <[hidden email]>:
Sorry, I'm not sure I fully understand your idea.
It looks like trying to make another implementation of UndefinedObject, is it?

What is the main difference between proposed MissingValue and UndefinedObject?

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. 
Reply | Threaded
Open this post in threaded view
|

Re: Protego - smart way to manage NIL's in business calculations

Denis Kudriashov

2016-12-18 20:19 GMT+01:00 Denis Kudriashov <[hidden email]>:

What is the main difference between proposed MissingValue and UndefinedObject?

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. 

And it makes impossible to distinguish bug from normal application state related to missing value 
Reply | Threaded
Open this post in threaded view
|

Re: Protego - smart way to manage NIL's in business calculations

Ben Coman
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.
>>
>

Reply | Threaded
Open this post in threaded view
|

Re: Protego - smart way to manage NIL's in business calculations

Stephane Ducasse-3
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:

2016-12-18 20:19 GMT+01:00 Denis Kudriashov <[hidden email]>:

What is the main difference between proposed MissingValue and UndefinedObject?

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. 

And it makes impossible to distinguish bug from normal application state related to missing value