Hello everyone. I'm a newbie with a question whose answer is probably obvious, but I'm too thickheaded to figure it out, so here goes... We can say "cba".reverse or x.reverse and get "cba". Also x.upcase or "abc".upcase and get "ABC". So it's pretty clear that x and "abc" are objects, because we're able to use methods to send messages to them. But when I do x.print or "abc".print it throws an error. I have to use print x or print "abc", which seems to violate the "least surprise" principle and causes sleep deprivation in clueless newbies like me. Also, things like print x.upcase.reverse just drive me up a wall. Why not x.upcase.reverse.print? Can anyone help?
on 2012-08-15 18:17
on 2012-08-15 18:29
Because print is not a object from the String class. So I'm going to do
what you want(save the following code as string_print.rb):
# Ruby has open classes so I can open a already existing class, like of
String, and declare methods to it
class String
def print
puts self
eld
end
"abcd".reverse.print
# I hope you enjoyed.
on 2012-08-15 18:29
Woops, typo.
# Ruby has open classes so I can open a already existing class, like of
String, and declare methods to it
class String
def print
puts self
end
end
"abcd".reverse.print
# I hope you enjoyed.
on 2012-08-15 18:39
On Wed, Aug 15, 2012 at 11:28 AM, Thiago Massa <thiagown@gmail.com> wrote: > Because print is not a object from the String class. So I'm going to do what > you want(save the following code as string_print.rb): No; it's a method from Object (mixed in from Kernel, I believe). It's a private method, so you can't use dot notation on it; the actual receiver is the "main"/"toplevel" object, which happens to be an Object. I'm not sure what languages actually have a print-type method defined on instances like that, but there must be some. Languages like Java and Smalltalk define their text output methods on instances of IO streams; you can actually do that in Ruby too, using something like `$stdout.print foo`. But I guess printing values is so common that Matz decided to basically follow the example of Perl and other languages for which output is done with something appearing more like a command or statement than a method.
on 2012-08-15 19:46
Eric Christopherson wrote in post #1072456: > Languages like Java > and Smalltalk define their text output methods on instances of IO > streams; you can actually do that in Ruby too, using something like > `$stdout.print foo`. The OO conundrum again - function acting on two objects, which object class does the function belong in? It could be either. If it were string.print and you wanted to send to a different stream, you would need to do something like "hello".print($stdout) which would work fine - Reia works this way <http://reia-lang.org/> However I can think of one good reason for doing it the Ruby way round. print/puts expects a string, and it will call to_s automatically on the argument if it is not. "foo.print" would fail on any object which doesn't have a print method - or there would have to be a print method in the top-level Object which does to_s.print. The latter would mix a public 'print' method into every object - and also risks infinite recursion if to_s doesn't actually return a string. Having a public to_s method is more generally useful than a public print method, I think. Regards, Brian.
on 2012-08-16 01:49
On 16/08/2012, at 4:17 AM, Fred McArthur wrote: > But when I do x.print or "abc".print it throws an error. I have to use > print x or print "abc", which seems to violate the "least surprise" > principle and causes sleep deprivation in clueless newbies like me. > Also, > things like print x.upcase.reverse just drive me up a wall. Why not > x.upcase.reverse.print? I know it's a common example in OOD text books, that an object has a print method (or draw or display), but that design is wrong. "abc".print makes the assumption that String has knowledge of where and how it will be 'printed'. String's print implementation will have be able to print to all known output devices. If another output device is invented String will have to be updated or it won't be able to print to it. Sure you could do "abc".print( device) but that will put unnecessary restrictions on the devices interface. The correct way to do this is have each device know which types it can print and how to print them. $stdout.puts "abc" The MVC pattern works this way. Ruby has done the correct thing. Henry
on 2012-08-16 02:02
On Wed, Aug 15, 2012 at 4:48 PM, Henry Maddocks <hmaddocks@me.com> wrote: > I know it's a common example in OOD text books, that an object has a print > method (or draw or display), but that design is wrong. [...] Ruby has done > the correct thing. > Oh has it now? 1.8.7 :001 > "Hello world!".display Hello world! => nil
on 2012-08-17 05:29
Thanks for responding. I'll have to think it over before really grasping why it's done the way it's done. The example for extending class String works well enough. But why it's not done that way in the first place still escapes me. For instance, I understand the statement: ### "foo.print" would fail on any object which doesn't have a print method But so would reverse, upcase, downcase and all the other methods that ARE done with dotted notation. Also if print is a private method, then why aren't the others? I gather it has a lot to do with selection of output devices, but isn't the idea of OO based in part on polymorphism, therefore able to handle that (I'm taking a wild shot here)? (No doubt I'll get it when I reread the responses again.) Lots to think about here. Thanks for everyone's input!
on 2012-08-17 06:23
So initially I said that Thiago Massa's class String extension worked,
and it does to a point. But not for numbers, at least not without
further mods.
class String
def print
puts self
end
end
"abcd".print # This works
1.print # This causes a Fixnum error
because "print/puts expects a string,and it will call to_s automatically
on the argument if it is not."
What's nice about the standard "print" is that conversion is automatic.
No need to convert a non display number to display type in order to
print it. Saves a lot of work.
and then there's this:
"Hello world!".display # This works fine!
on 2012-08-17 10:51
Am 17.08.2012 06:23, schrieb Fred McArthur: > "abcd".print # This works > > 1.print # This causes a Fixnum error Of course, since there is no print method in the Fixnum class. You would have to monkey patch that, too. > because "print/puts expects a string,and it will call to_s automatically > on the argument if it is not." Only the print method from the kernel will do that, but 1.print tries to invoke the print method from Fixnum. You would have to define a print method for *all* the classes that you want to work with. > What's nice about this is that it's automatic. No need to convert a non > display number to display type in order to print it. Saves a lot of > work. Please keep in mind that too much monkey patching might be counterproductive or even dangerous. In your case it does *not* save you any work, rather the contrary. And locating errors might get more difficult. I would *highly* recommend to simply stick with: print 'abc' print 1 puts 'result: ' << (1+2).to_s puts "result: #{1+2}" (There is no need to reinvent the language.)
on 2012-08-17 11:07
Fred McArthur wrote in post #1072622: > But why it's not done that way in the first place still escapes me. For > instance, I understand the statement: > > ### "foo.print" would fail on any object which doesn't have a print > method > > But so would reverse, upcase, downcase and all the other methods that > ARE done with dotted notation. Also if print is a private method, then > why aren't the others? I gather it has a lot to do with selection of > output devices, but isn't the idea of OO based in part on polymorphism, > therefore able to handle that (I'm taking a wild shot here)? With polymorphism you probably mean that the method acts differently depending on the output device. The problem with this is that you certainly don't want to hardcode the output logic for some devices into your method. This wouldn't make any sense (as Henry already said). So the method would have to delegate the call to the output object. In other words, you need two different methods: IO#print(String) --> the actual output logic String#show(IO) --> for printing a string-like object on a device This actually makes a lot of sense. And as you've already seen, that's pretty much what Ruby does with "print" and "display". The only criticism I can think of is that the top level "print" should be removed. This would force you to either write $stdout.print("Hallo") or "Hallo".display instead of using this pseudo-imperative style.
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.