3 ms·
> integers are much more primitive than date and time objects In terms of concepts, yes, but in terms of language syntax and semantics they are the same (in Sm
by klibertp 13y ago
> integers are much more primitive than date and time objects
In terms of concepts, yes, but in terms of language syntax and semantics they are the same (in Smalltalk).
> `2.days` is okay, `2.days.ago` is right out
Yeah. But not because it "looks bad", and not because Integer would need to know anything more than it does already (it wouldn't), but because `2 days ago` is actually less flexible and harder to maintain.
Consider:
Date today - 2 days. "27 December 2013"
DateAndTime now - 2 days. "2013-12-27T04:43:42.679+01:00"
We can get either Date or DateAndTime without changing anything. With proper planning the superclass of both Date and DateAndTime can have a generic - method which will work for all the cases. With the `2.days.ago` we're tied to one result type. We need to code around it, giving it a default argument with a class or remembering the "kind" of Duration.
Anyway, if it's ok to have a function which takes integer it's equally ok to have an Integer have a method. Especially when you just can't have a function, like in Smalltalk and the only alternative is writing yet another class with one method in it.
- philwelch 13y ago> Anyway, if it's ok to have a function which takes integer it's equally ok to have an Integer have a method. Seriously? Any function that takes an integer argument? Like, "exit". You want to call 1.exit to terminate a program with a return code of 1? Is there any difference between a function that takes an argument and a method on an object? Shall we implement all functions that take n arguments as multimethods? Are you actually going to implement String#to_database_connection? That was meant as a reductio ad absurdum, I didn't expect anyone to literally follow me there. If you want some particular Integer to get decorated with additional methods because you're using it in some particular domain context but you're not globally changing the interface of all Integers that's a different story. > Especially when you just can't have a function, like in Smalltalk and the only alternative is writing yet another class with one method in it. There are perfectly same object oriented ways to solve this problem, like instantiating some kind of TimeSpan object, or having a singleton for process status in the case of the "exit" function.
- klibertp 13y ago> You want to call 1.exit to terminate a program with a return code of 1? 1.exit is a bad idea because it has a side effect outside of it's receiver, I think. > Are you actually going to implement String#to_database_connection? Yeah. Or at the very least I won't die when I see this (working code in Pharo 2.0): 'http://example.com' asZnUrl retrieveContents. "connect to given url and fetch it's contents" or this: 'HelloWorld' asMorph openInHand. "create a bitmap representation of string and display it on screen where the cursor is" or this: #asSet value: (Array with: 1 with: 1 with: 3). "Symbol>>value:anObject looks like this: anObject perform: self" which is especially interesting: how come a Symbol knows how to perform an action it can represent on some given object? I dunno. It just does. I can't tell you exactly when adding a method to some class begins to be a bad idea and when it's still ok to do. I don't know any hard rule for this. I agree that `1.exit` is a bad idea and I provided a rationale for why I think so. But I'm still convinced that there are many (many more than you seem to think) cases where it's ok, it's acceptable and convenient to extend String, or Object, or any class you don't "own". I'm actually looking at the system which is built with very many methods like the examples above (although it doesn't have 1.exit) and I see that it works. One of the most basic classes, Object, has this many external (with extension methods) protocols in it: *Collections-Abstract-splitjoin, *Fuel, *Fuel-Collections, *Glamour-Helpers, *Graph-ET-Core, *Graphics-Display Objects, *Kernel-Exceptions-debugging, *Monticello-Storing, *Morphic, *NativeBoost-Examples, *NativeBoost-core, *Nautilus, *Polymorph-EventEnhancements, *Polymorph-TaskbarIcons, *Polymorph-Widgets, *Ring-Core-Kernel, *Shout-Parsing, *Soup-core-testing, *Spec-Core, *Spec-Tools, *System-Settings-Browser, *System-Support, *Tools-Base, *Tools-Browser, *Tools-Explorer, *Tools-Finder, *Tools-Inspector, *UIManager, *VMMaker-translation support, *collectionextensions, *deprecated20, *eyesee-support, *grease-core, *grease-pharo20-core, *magritte-model-accessing, *magritte-model-actions, *magritte-model-model, *magritte-model-testing, *magritte-morph-converting, *metacello-core, *mondrian-complexshape, *mondrian-core-accessing, *mondrian-fadelayout, *necompletion-extensions, *neo-json-core, *petitparser-core-converting, *petitparser-core-testing, *roassal-core, *rubric, *tools-debugger And the system still works. And it's easy to navigate. And to understand. And to use, even. So, once again - I'm not arguing that 1.exit is ok, just that there are many "saner" extension methods which are ok. To get the above list I had to write some code: |allProtocolNames externalProtocols| allProtocolNames := (Object allMethods collect: [ :x | x category asString]) asSet asSortedCollection. externalProtocols := (allProtocolNames select: [ :x | x beginsWith: '*' ]) inject: Character cr asString into: [:acc :x | acc , x , Character cr asString ]. Transcript show: externalProtocols. I may not be very experienced Smalltalker, but I believe this is more or less idiomatic Smalltalk code. Even in this short snippet there are 3 asSomething methods - and the code still works and I still think it's readable. And cute. Is it Smalltalk specifically which enables this technique or what other rules extension methods need to follow to be sane I don't know. Which is why I'm hesitant to implement those methods myself. But I accept their existence and the fact that they have their place in a sound, sane design, at least if done right (for any acceptable value of "right" we can agree on). But well, my day to day job is writing Python, where "monkey patching" is considered a sin and the community consensus is pretty much the same as your opinion: don't extend classes, write functions instead. So I kind of understand this position. Although I still think it's not inherently bad idea to extend base classes and that it's the matter of language design, project design and tooling. But I can't say for sure. I'm just telling you what I saw when I went and learned Smalltalk, that's all.