[LRUG] Comparable Null Objects

Duncan Stuart dgmstuart at gmail.com
Wed Jul 15 08:34:20 PDT 2015


Thanks John

Yeah - that's pretty much what I suggested at the end of my original post.
The reason I wanted to try and find another way is because it has that
typecheck on expected_date, which seems to negate the benefits of using a
renderable NullObject in the first place.

I feel like Tim's approach of events.sort_by { |event| event.expected_date
|| Float::INFINITY } would be preferable if dealing with it at the Event
level.


On 15 July 2015 at 16:16, <jc at panagile.com> wrote:

> Hmm, if you’re sorting a list of events then why not let the event’s
> control how the comparison works? E.g., something like:
>
>  require 'date'
>
> class NoExpectedDate
> end
>
> class Event
>   attr_reader :expected_date
>
>   def initialize(date)
>     @expected_date = date
>   end
>
>   def unsortable?
>     expected_date.is_a?(NoExpectedDate)
>   end
>
>   def <=>(other)
>     if self.unsortable?
>       1
>     elsif other.unsortable?
>       -1
>     else
>       self.expected_date <=> other.expected_date
>     end
>   end
> end
>
>
> e1 = Event.new(Date.today)
> e2 = Event.new(NoExpectedDate.new)
> e3 = Event.new(Date.today - 1)
>
> [e1, e2, e3].sort # => [#<Event:0x007f968511a3c8 @expected_date=#<Date:
> 2015-07-14 ((2457218j,0s,0n),+0s,2299161j)>>, #<Event:0x007f968511a490
> @expected_date=#<Date: 2015-07-15 ((2457219j,0s,0n),+0s,2299161j)>>,
> #<Event:0x007f968511a440 @expected_date=#<NoExpectedDate:0x007f968511a468>>]
>
>
> This is still pretty imperative, but that’s probably a good thing in this
> case. The pure OO approach to this gets nasty quickly.
>
>
>
> On Wed, Jul 15, 2015 at 3:54 PM, Duncan Stuart <dgmstuart at gmail.com>
> wrote:
>
>> Thanks John
>>
>> * I want to sort things of the same type (instances of the Event class).
>> * I want to sort them *by* an attribute containing things which Quack
>> enough like dates to be sorted against each other
>> * I want to do this so that they're displayed in date order in an email
>> * Yes, it's an Array. I could create an EmailEventCollection object which
>> I would tell "give me the things for my email" and it would respond with an
>> array which was (amongst other things) sorted, but I don't think that would
>> resolve the issue at hand: it hides the mess in a different way, but
>> internally I'd still be doing the same sort, no?
>>
>> On 15 July 2015 at 15:09, <jc at panagile.com> wrote:
>>
>>>
>>> | Some events don't have an expected date, so like a good little OO
>>> programmer i've created a Null object:
>>>
>>> Yay! Good OO programmer.
>>>
>>> | but when it comes to sorting the list
>>>
>>> wait, wat? Less good OO programmer.
>>>
>>> I can see three things going on here, pretty much simultaneously.
>>>
>>> 1) You want to sort a list of different types of things. Like when you
>>> try to sort a list of Silverback Gorillas and instances of the number 37
>>> it’s hard because it doesn’t really make sense.
>>>
>>> 2) You don’t have a list. You have an Array object. Is this the best
>>> place to send the ‘sort’ message to? Should it own the behaviour of sorting
>>> these particular disparate types of things?
>>>
>>> 3) You switched from clean OO thinking (we need an object to encapsulate
>>> this state) to imperative thinking (we have a list and we need to sort it).
>>>
>>> I blame Ruby for all of this. It makes you think you’re doing OO
>>> programming but throws in many non-OO ideas to trip you up.
>>>
>>> It’s not clear that an OO approach is the best approach here, but if you
>>> want to follow it try to think less about objects and more about the
>>> messages between objects. E.g., instead of ‘I need to sort a list’ think ‘I
>>> need to send a message somewhere telling it to do something (in this case
>>> to… what? To sort some objects? But why do you care?)’.
>>>
>>> Hope this helps or at least makes you think or at the very least
>>> persuades you to rage quit programming and go and live in a forest,
>>> John
>>>
>>>
>>> On Wednesday, Jul 15, 2015 at 1:03 pm, Duncan Stuart <
>>> dgmstuart at gmail.com>, wrote:
>>>
>>>> Hi LRUG - hopefully an interesting little problem:
>>>>
>>>> I have an Event class which has an "expected_date" attribute.
>>>> Some events don't have an expected date, so like a good little OO
>>>> programmer i've created a Null object:
>>>>
>>>> class NoExpectedDate
>>>>   def to_s(format=:default)
>>>>     "Unknown"
>>>>   end
>>>> end
>>>>
>>>> This works great for printing the values, but when it comes to sorting
>>>> the list I of course get:
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>    ArgumentError: comparison of Date with NoExpectedDate failed
>>>>
>>>> If I include Comparable and define <=> then one comparison works, but
>>>> the other doesn't :
>>>>
>>>> class NoExpectedDate
>>>>   include Comparable
>>>>   def to_s(format=:default)
>>>>     "Unknown"
>>>>   end
>>>>   def <=>(other_date)
>>>>     1 # Treat it as after every other date
>>>>   end
>>>> end
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> $ NoExpectedDate.new > Date.today
>>>> => true
>>>>
>>>>
>>>> $ Date.today > NoExpectedDate.new
>>>> ArgumentError: comparison of Date with NoExpectedDate failed
>>>>
>>>> I think this is because Date's <=> method expects it's argument to be a
>>>> Date object or a number ("a numeric value as an astronomical Julian day
>>>> number"). I've tried defining to_i and to_r on NoExpectedDate, but no dice.
>>>>
>>>> Can I get NoExpectedDate to pretend to be a Date (like SimpleDelegator
>>>> lies about it's class)? Is that evil?
>>>>
>>>> I suppose I could always just define a method on Event to do this
>>>> particular sort, but that seems nasty for all sorts of reasons:
>>>>
>>>> def sort_by_expected_date sort do |a, b|
>>>>
>>>>     if b.class = NoExpectedDate
>>>>
>>>>       1
>>>>
>>>>     else
>>>>
>>>>       a <=> b
>>>>
>>>>     end
>>>>
>>>>   end
>>>>
>>>> end
>>>>
>>>>
>>>>
>>> _______________________________________________
>>> Chat mailing list
>>> Chat at lists.lrug.org
>>> Archives: http://lists.lrug.org/pipermail/chat-lrug.org
>>> Manage your subscription:
>>> http://lists.lrug.org/options.cgi/chat-lrug.org
>>> List info: http://lists.lrug.org/listinfo.cgi/chat-lrug.org
>>>
>>>
>>
>
> _______________________________________________
> Chat mailing list
> Chat at lists.lrug.org
> Archives: http://lists.lrug.org/pipermail/chat-lrug.org
> Manage your subscription: http://lists.lrug.org/options.cgi/chat-lrug.org
> List info: http://lists.lrug.org/listinfo.cgi/chat-lrug.org
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lrug.org/pipermail/chat-lrug.org/attachments/20150715/0b486d9c/attachment-0003.html>


More information about the Chat mailing list