<span id="mailbox-conversation"><div>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:</div>
<div><br></div>
<div>
<div>require 'date'</div>
<div><br></div>
<div>class NoExpectedDate</div>
<div>end</div>
<div><br></div>
<div>class Event</div>
<div> attr_reader :expected_date</div>
<div><br></div>
<div> def initialize(date)</div>
<div> @expected_date = date</div>
<div> end</div>
<div><br></div>
<div> def unsortable?</div>
<div> expected_date.is_a?(NoExpectedDate)</div>
<div> end</div>
<div><br></div>
<div> def <=>(other)</div>
<div> if self.unsortable?</div>
<div> 1</div>
<div> elsif other.unsortable?</div>
<div> -1</div>
<div> else</div>
<div> self.expected_date <=> other.expected_date</div>
<div> end</div>
<div> end</div>
<div>end</div>
<div><br></div>
<div><br></div>
<div>e1 = Event.new(Date.today)</div>
<div>e2 = Event.new(NoExpectedDate.new)</div>
<div>e3 = Event.new(Date.today - 1)</div>
<div><br></div>
<div>[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>>]</div>
</div>
<div><br></div>
<div><br></div>
<div>This is still pretty imperative, but that’s probably a good thing in this case. The pure OO approach to this gets nasty quickly.</div></span><div class="mailbox_signature"><br></div>
<br><br><div class="gmail_quote"><p>On Wed, Jul 15, 2015 at 3:54 PM, Duncan Stuart <span dir="ltr"><<a href="mailto:dgmstuart@gmail.com" target="_blank">dgmstuart@gmail.com</a>></span> wrote:<br></p><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div><div dir="ltr">Thanks John<br><br>* I want to sort things of the same type (instances of the Event class).<div>* I want to sort them *by* an attribute containing things which Quack enough like dates to be sorted against each other</div>
<div>* I want to do this so that they're displayed in date order in an email</div>
<div>* 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?<br><div class="gmail_extra">
<br><div class="gmail_quote">On 15 July 2015 at 15:09, <span dir="ltr"><<a href="mailto:jc@panagile.com">jc@panagile.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<u></u>
<div>
<span><span class=""><div><br></div>
<div>| Some events don't have an expected date, so like a good little OO programmer i've created a Null object:</div>
<div><br></div>
</span><div>Yay! Good OO programmer.</div>
<span class="">
<div><br></div>
<div>| but when it comes to sorting the list</div>
<div><br></div>
</span><div>wait, wat? Less good OO programmer.</div>
<div><br></div>
<div>I can see three things going on here, pretty much simultaneously.</div>
<div><br></div>
<div>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.</div>
<div><br></div>
<div>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?</div>
<div><br></div>
<div>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).</div>
<div style="display:block"><div>
<div><br></div>
<div>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.</div>
<div><br></div>
<div>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?)’.</div>
<div><br></div>
<div>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,</div>
<div>John</div>
<div><br></div>
</div></div>
<div><div class="h5">
<br><span style="display:inline">On Wednesday, Jul 15, 2015 at 1:03 pm, Duncan Stuart <<a href="mailto:dgmstuart@gmail.com">dgmstuart@gmail.com</a>>, wrote:<br></span>
</div></div></span><div><div class="h5">
<span><blockquote class="gmail_quote"><div><div dir="ltr">Hi LRUG - hopefully an interesting little problem:<br><br>I have an Event class which has an "expected_date" attribute.<br>Some events don't have an expected date, so like a good little OO programmer i've created a Null object:<br><br><div>class NoExpectedDate</div>
<div> def to_s(format=:default)</div>
<div> "Unknown"</div>
<div> end</div>
<div>end</div>
<div><br></div>
<div>This works great for printing the values, but when it comes to sorting the list I of course get:<br><br><br><br><br><br><br><br><br><br><br> ArgumentError: comparison of Date with NoExpectedDate failed <br><br>If I include Comparable and define <=> then one comparison works, but the other doesn't :<br><br><div>class NoExpectedDate</div>
<div> include Comparable</div>
<div> def to_s(format=:default)</div>
<div> "Unknown"</div>
<div> end</div>
<div> def <=>(other_date)</div>
<div> 1 # Treat it as after every other date</div>
<div> end</div>
<div>end</div>
</div>
<div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><p><span>$ </span><span>NoExpectedDate</span><span>.new > </span><span>Date</span><span>.today<br></span><span>=> </span><span>true</span></p>
<br><br><p><span>$ </span><span>Date</span><span>.today > </span><span>NoExpectedDate</span><span>.new<br></span>ArgumentError: comparison of Date with NoExpectedDate failed<br><br>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.<br><br>Can I get NoExpectedDate to pretend to be a Date (like SimpleDelegator lies about it's class)? Is that evil?<br><br>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:<br><br></p>
<p>def sort_by_expected_date sort do |a, b| </p>
<p> if b.class = NoExpectedDate </p>
<p> 1</p>
<p> else</p>
<p> a <=> b</p>
<p> end</p>
<p> end</p>
<p>end</p>
<p><br></p>
</div>
</div></div></blockquote></span>
</div></div>
</div>
<br>_______________________________________________<br>
Chat mailing list<br><a href="mailto:Chat@lists.lrug.org">Chat@lists.lrug.org</a><br>
Archives: <a href="http://lists.lrug.org/pipermail/chat-lrug.org" rel="noreferrer">http://lists.lrug.org/pipermail/chat-lrug.org</a><br>
Manage your subscription: <a href="http://lists.lrug.org/options.cgi/chat-lrug.org" rel="noreferrer">http://lists.lrug.org/options.cgi/chat-lrug.org</a><br>
List info: <a href="http://lists.lrug.org/listinfo.cgi/chat-lrug.org" rel="noreferrer">http://lists.lrug.org/listinfo.cgi/chat-lrug.org</a><br><br></blockquote>
</div>
<br></div>
</div>
</div></div></blockquote></div><br>