Strong advantages over Python

me: “yeah OO is great, it reflects real world!”
friend: “Sure. How do you make coffe?”
me: “well, I open the coffe machine and put in coffe and water,
put it on fire, wait and drink”

Person instance interacts w/ HeatSource instance which results in an instance
whose class mixes in Water and Coffee?

This reminds me of the (in)famous elevator control example quoted by
proponents of concurrent programming (erlang, specifically):

“I recall reading a flamewar somewhere about Erlang vs. OO languages. The
sample problem was a control system for three elevators. The Erlang person
claimed that Erlang matched the problem naturally, because you just create
three processes, one for each elevator, and make each respond to (callbutton
Floor), (door_open), and (door_close) messages. The OO person pointed out
that you could just as easily create three objects with the same methods and
get the same result. From an interface point of view, there’s no difference.
But try to actually implement this, with actual elevators going up and down
and motors starting and stopping. In Erlang, it’s about as complex as you’d
expect. In most OO languages it’s a nightmare, because the real world has
stuck it’s asynchronous nose in and suddenly you’ve got to deal with either
threads or a nasty control flow inversion.”

I love OO, but agree that different paradigms do, really, match up better in
certain circumstances… not that an ICBM missile control system wouldn’t be
fun to implement in Ruby (albeit scary). I’d just use Test::Unit copiously.
:wink:

// Bruce

···


author: Bruce R. Williams
url: http://codedbliss.com
irc: { nick: iusris, channel: [ruby-lang,yaml], server: irc.freenode.net }
quote: >
It does not require a majority to prevail, but rather an irate,
tireless minority keen to set brush fires in people’s minds.’
– Samuel Adams

Greg McIntyre wrote:

Debatable but okay. I would think about this point differently. Ruby has
a simple object model - objects are a bunch of variables and methods,
and Ruby gives you the means to add/subtract/edit them with a lot of
power.

Sounds like a description of Python to me. :wink:


This is something I love about Ruby over Python. I hate the Python
library reference – it’s so hard to find what you want to do using
it. Whereas on the off chance you actually need to look something up
while programming Ruby (as most things work by Ruby reading your mind),
you generally know exactly where to look for it.

If that’s your experience then you’re entitled to it! I sometimes find
the Python library messy but certainly no more so than Java or other
languages I have used. Perhaps Ruby is the exception, I’ve only tinkered
with it.

Some examples of the benefits of pure OOP. I use “have a nice day”.split
a fair bit, but Python can do that too so it makes it less enjoyable. :wink:
[‘dir1’, ‘dir2’, ‘filename’].join(File::Separator) might be a better
example.

import os
print os.sep
/
os.sep.join([“dir1”, “dir2”, “dir3”])
‘dir1/dir2/dir3’
print type(os.sep)
<type ‘str’>

This also relates to the fact that you generally know where to look for
a particular method in Ruby. In Python, join is a function defined in
the string module.

Several versions of Python ago. This was changed in Sept 2000.

http://www.python.org/doc/current/lib/string-methods.html
http://www.python.org/1.6/

Python 2.2 is a bit better. They’re still not the same however. AFAIK
you use lambdas in Python to create closures (assigning the lambdas to
variables and calling them later on).

This is incorrect. Lambdas are syntactic sugar for function definitions.
There is nothing you can do with lambdas that you could not do with
regular functions.

… But lambdas expect ‘expressions’
not ‘statements’ meaning you can only do a very limited number of things
in your Python closure. Also, you cannot assign to a variable which is
in a closure’s context but outside its direct scope (e.g. something
assigned just above a Ruby block).

That much is true. IMHO it’s pretty rarely needed in object oriented
programming but it is nevertheless true that it is clunky in Python.

In Python you can assign function names to variables and then call them
through those variables, however AFAIK this relies on separate function
definitions and global variables in order to achieve the same level of
context manipulation possible with a Ruby block, so it certainly isn’t
as clean and easy.

I’m having trouble following this bit. It’s true that you can’t directly
overwrite a variable in a surrounding context. I don’t know that this
has anything to do with assigning function names to variables or global
variables or anything. The usual workaround is to mutate an object
rather than overwriting a variable.

def a():
state = {}
def putin(x):
state[“something”] = x
def getout(x):
return state[“something”]
return putin, getout

But every example I see of this seems contrived to me. You’re trying to
build a “thing” which has both mutable state and functional behaviour.
Well, in OO languages we tend to call those things objects.

class a:
def putin(self, x):
self.something = x
def getout(self, x):
return self.something

I’d appreciate it if the more Python-inclined could correct or confirm
all that.

Hope that helps.

Just out of curiousity, will there be anybody at this university
describing the things Python can do better than Ruby? It sounds like the
professor is not knowledgable enough to do that. Perhaps he wants you to
present both sides?

Paul Prescod

Ruby has closures, Python does not. Not getting into the “who’s better”
argument; just citing a fact.

···

On Saturday 22 March 2003 06:48 am, Greg McIntyre wrote:

Jim Weirich jweirich@one.net wrote:

Thanks Paul. Sometimes its easy for those of us who are very familiar
with Ruby to neglect features of a language we are less familiar with.

Yes, this was the case. I do not want to propagate misinformation.

It sounds to me as if the original poster is looking for a “slam dunk”
for Ruby (compared to Python), and I’m not sure he’s going to find
one.

Well, in my defense, it wasn’t me who was looking for such a thing. I’m
a much more subtle person. :wink: My lecterer wanted a “slam dunk” and was
perhaps using a straw-man tactic to argue Python’s equivalence. What I
want are a few benefits Ruby has in practice over Python. Not
necessarily technical capabilities (which are usually obscure) but
features which are frequently taken advantage of by its programmers
where the equivalent Python is not impossible, but significantly more
difficult.

Ruby and Python have far more in common than they have
differences. What differences there are more more differences in
preferences than real differences in language power.

They are very similar but since researching the differences I’ve found
that there are significant differences in common practice adopted by
Ruby and Python programmers. Ruby’s learning curve is decidedly easier,
for example, due he POLS and its small, powerful and reasonably
consistent standard library which owes a lot to Ruby’s more pure
O-O-ness. Ruby blocks also lend themselves to so many useful things,
and are used so extensively in Ruby, I think it’s very significant.

That is, in terms of what the languages can do, they’re almost exactly
the same. In terms of the nature of the code frequently written in each
language, they’re quite different.


Seth Kurtzberg
M. I. S. Corp.
480-661-1849
seth@cql.com

dblack@superlink.net wrote:

Besides, as many have said before me, Ruby is full of surprises; they
just happen to be pleasant surprises :slight_smile:

… which in itself is a very big surprise. (Unpleasant surprises aren’t
that surprising when programming.)

I wonder if recoining PoLS as “Principle of Lovely Surprises” would be
the best bet :slight_smile:

···


([ Kent Dahl ]/)_ ~ [ http://www.stud.ntnu.no/~kentda/ ]/~
))_student
/(( _d L b_/ NTNU - graduate engineering - 5. year )
( __õ|õ// ) )Industrial economics and technological management(
_
/ö____/ (_engineering.discipline=Computer::Technology)

[…[

I skipped over a lot of this discussion, but did anyone mention space-
sensitive syntax? It’s so nice to be able to put

if false

end

around a piece of code, and not have to re-indent the whole lot!

I suspect that despite all the technical differences between Ruby and
Python, the indentation issue is single largest reason for prefering one
over the other.

···

On Sun, 2003-03-23 at 17:58, Brian Candler wrote:


– Jim Weirich jweirich@one.net http://w3.one.net/~jweirich

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Now I’m responding to my own messages, which is dangerously close to
talking to myself. But another, more common, problem where generators
have the advantage is trying to iterate over two lists in parallel.

···

On Sun, 2003-03-23 at 17:55, Jim Weirich wrote:

This problem is was easy to convert because the basic loop is easy to
unroll. If the algorithm were more deeply nested, or used yield in
multiple locations, the conversion would be more obscure. For example,
a generator that returned the leaves of a tree data structure would be
fairly easy using generators, but more difficult without.


– Jim Weirich jweirich@one.net http://w3.one.net/~jweirich

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Okay, so what if, instead of saying “This functionality has been added
to Python recently as generators,” I said that “This functionality has
been added to Python recently using generators”? I mean. If generators
are a more powerful and general construct, they should be able to do
what Ruby blocks can, plus more.

···

Jim Weirich jweirich@one.net wrote:

Yes and no. Although they are entirely different things, they both
are used for do “iteration-like” stuff in their respective languages.
That and the fact they both use the keyword “yield” (although with
complete different semantics!) leads people to confuse the two.


Greg McIntyre
greg@puyo.cjb.net
http://puyo.cjb.net

Actually, the PoLS only applies to matz… :slight_smile:

···

Greg McIntyre greg@puyo.cjb.net wrote:

Paul Prescod paul@prescod.net wrote:

Is this really how a Ruby programmer would characterize POLS? To be
honest, the way you state it, I wouldn’t be interested in either
Python or Ruby. A language that tries to cater to everyone’s tastes
is doomed to failure. Sounds like the popular image of Ada!

Hrm… perhaps the description I’ve given is a little silly. It’s one
thing to be flexible and expressive, but another to try to please
everybody.


Greg McIntyre
greg@puyo.cjb.net
http://puyo.cjb.net

Hi –

So I have implicity “defined” a duck type without ever making a Duck
class. In Java I would need a class or an interface or something, but
in Ruby that’s all behond the scenes.

Er… in this example you have an object of class String with an extra
method. IMO, this is still of class String. I don’t address singleton
methods in the lecture. Should I? I’ve never used them and I very rarely
see others using them. Are they that important to be included in a quick
intro of Ruby?

I think the underlying principle – that the capacity of an object
does not depend on its historical class (which is at the heart of the
“duck typing” thing and the characteristic downplaying of type in
Ruby) – is important and also conveys a lot of the flavor of the
language. So I’d root for saying something about it if you can
without feeling like you’re losing the forward motion of the overview.

And of course if you mention class methods, you’ve mentioned singleton
methods :slight_smile:

David

···

On Mon, 24 Mar 2003, Greg McIntyre wrote:


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Brian Candler wrote:

You can write that almost exactly the same in Ruby of course: substitute
proc { |foo| … } for lambda foo:

Right, you’ve wrapped the block in a function. It strikes me as a minor
wart (of the same sort that all languages have) that if you want to pass
a single closure you use block syntax but if you want to pass multiple
you switch to procs. I guess that keeps the syntax simpler.

But Ruby gives you other choices. You could pass a method of an existing
object, e.g. $stdout.method(:write) and $stderr.method(:write)

FYI, this also works for Python. I was just trying to generate an
example that took multiple blocks but you’re right, that wasn’t the best
one.

somefunc(sys.stdout.write, sys.stderr.write)

As far as I know, there is nothing in Python that can be named but
cannot be passed to a function or assigned to a variable. In that sense,
everything in Python is an object, even methods.

def help_start(title, obj):
print title, type(obj)
print obj
print “”.join(obj.doc.splitlines()[0:2])
print

import sys

help_start(“module object”, sys)
help_start(“file object”, sys.stdout)
help_start(“method object”, sys.stdout.write)
help_start(“class object”, sys.stdout.class)
help_start(“string object”, sys.stdout.doc)

If I were writing the above, rather than passing in two functions, I’d
probably just pass in two IO-like objects, and call output_obj.write and
error_obj.write respectively.

That’s why it is a little silly that we spend so much time talking about
the functional bits of the languages. (e.g. closures, generators,
blocks, etc.) Of course Python also has a “.write” convention for file
objects.

I skipped over a lot of this discussion, but did anyone mention space-
sensitive syntax? It’s so nice to be able to put

if false

end

around a piece of code, and not have to re-indent the whole lot!

In Python you would put “”" around it to achieve the same effect.

Paul Prescod

Hi –

‘self’ is the first parameter in a Python method. Because Ruby doesn’t
do things this way, (perhaps something I should note on the slides),
it has to define ‘self’ as a special constant, but also has the @
prefix as a shortcut (for ‘self.’).

No, @ is the prefix for instance variables. It’s not the same as
‘self’.

class A
def method(arg0, arg1, …, argN)
@x = something
self.x = something # also valid

Only if there’s a method called x=(), which there isn’t in this
example. You’d have to do:

class A
def x=(n)
@x = n
end

end

or:

class A
attr_writer :x # shortcut for the same thing

end

Otherwise you’re just calling a method that doesn’t exist, and you’ll
get an exception. The relation between @var and var=() is common, but
it still has to be established explicitly.

David

···

On Mon, 24 Mar 2003, Greg McIntyre wrote:


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

(This might also have implications for the equivalence you draw
between “self.attribute” in Python and “@attribute” in Ruby, but
I’m not sure exactly what’s going on on the Python side there.)
‘self’ is the first parameter in a Python method. Because Ruby
doesn’t do things this way, (perhaps something I should note on
the slides), it has to define ‘self’ as a special constant, but
also has the @ prefix as a shortcut (for ‘self.’).

@foo and self.foo are two different things. @foo refers to the
variable; self.foo refers to a method ‘foo’.

class A
def method(arg0, arg1, …, argN)
@x = something
self.x = something # also valid
end
end

irb(main):001:0> class A
irb(main):002:1> def method(arg)
irb(main):003:2> @x = arg
irb(main):004:2> self.x = arg
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> a = A.new
=> #<A:0x283f468>
irb(main):008:0> a.method(1)
NameError: undefined method x=' for #<A:0x283f468> from (irb):4:in method’
from (irb):8
irb(main):009:0>

self.foo (and self.foo=) is only usable if you have
attr_accessor :foo
somewhere in the class definition.

-austin
– Austin Ziegler, austin@halostatue.ca on 2003.03.23 at 21:42:21

···

On Mon, 24 Mar 2003 11:14:40 +0900, Greg McIntyre wrote:

dblack@superlink.net wrote:

Ruby objects are strongly typed (all types are known at compile
time); variables, however, are untyped.

-austin
– Austin Ziegler, austin@halostatue.ca on 2003.03.23 at 21:48:47

···

On Mon, 24 Mar 2003 11:14:59 +0900, Greg McIntyre wrote:

Mark Wilson mwilson13@cox.net wrote:

Slide 3, bullet point 1: Ruby is strongly typed (all objects have
a type) and dynamically typed (type is determined at run time).
Hrm… let’s ask the trusty old FOLDOC…

http://foldoc.doc.ic.ac.uk/foldoc/foldoc.cgi?strongly+typed
http://foldoc.doc.ic.ac.uk/foldoc/foldoc.cgi?weakly+typed

It seems Ruby is neither, although there is no definition for
“loosely typed” which I may have invented. :\

Er… in this example you have an object of class String with an extra
method. IMO, this is still of class String.

···

----- Original Message -----
From: “Greg McIntyre” greg@puyo.cjb.net

So I have implicity “defined” a duck type without ever making a Duck
class. In Java I would need a class or an interface or something, but
in Ruby that’s all behond the scenes.


Yes, its class is still String. I was talking about its type (or its
many types).

Consider the following C++ code:

class Point
{
int x;
int y;
}

int getXfromPoint (Point p)
{
return p.x;
}

(Bare with me; my C++ is rusty!) The function getXfromPoint accepts as its
argument the type Point, which is exactly those objects of class Point.

Now consider the Ruby version:

class Point
attr_accessor :x, :y
end

def getXfromPoint (p)
p.x
end

What is the type accepted by getXfromPoint this time? It is incorrect to
say that it would accept anything. It accepts any object which responds to
the `x’ method. It accepts any object it can!

So in Ruby, Point is a type (I guess), but so is
objects-which-respond-to-`x’, which has no associated class.

Going back to the original example, of course it was still a string, but
after `quack’ was defined, it was also a duck. Moreover, I could create a
string type (i.e. an object which responds to every method a string does)
which is not an instance of the String class:

myString = Object.new

class << myString
def reverse

end

def downcase
  ...
end

...

end

Of course, if you want to avoid singletons, I could have done the same in a
normal class:

class MyString
def reverse

end

...

end

That, as I understand it, is “duck typing”, and why we say that types and
classes are two different things in Ruby.

Chris

It’s beyond the scope of the excellent slides, but here goes my $0.02
on types:

Ruby has types. In Ruby, they are generally called classes.
Conceptually, there should not be a distinction between type and class
and this is certainly true of Ruby.

A type is “a set of values from which a variable, constant, function,
or other expression may take its value.” In the case of Ruby, only
objects have type and all objects have type. This is because every
“thing” in Ruby is an object. Ruby includes built-in types and a
user-defined types. User-defined types can extend or constrain built-in
types and can be entirely different than built-in types. Note that, in
Ruby, a class defines a set of values that an object may take.

In Ruby, all type rules are strictly enforced with no exceptions at the
time that a method is applied to an object. While this does not appear
to be “strong” typing according to the foldoc definition, it is
certainly stronger typing than would be the case if type rules are not
strictly enforced with no exceptions. As you noted, Ruby certainly does
not meet the definition of a weakly typed language either.

I don’t know about how Ruby handles the abstract syntax tree created by
the interpreter when a program is run to know for sure whether type
rules are enforced at Ruby’s analog to compile time (creation of the
abstract syntax tree).

As noted in the foldoc definition of strong typing, “with variables
that can store values of more than one type, incorrect type usage can
be detected at run time.” This is the principal difference between the
treatment of types in Ruby vs. that in Java.

In Ruby, it is impossible to create an object that does not have a
valid type, because an object is always an instance of a class – in
other words, a “thing” in the programming language is made by a type
generator and, by definition, has only values within the domain of that
type. I do think this is the functional equivalent of strong typing,
although the definitional issue is obviously of far less importance
than what Ruby actually does.

Because of the absence of (mandatory) type declaration for variables,
it is possible in Ruby to create an object and assign it to a variable
and then attempt to apply a method (operator) to that variable that is
not available to the type (class) of that object. This generates a run
time type error (although it is often called a “method missing” error).

For me, this is a better approach because it makes it easier to learn
how to write programs. As I understand it (not very well yet) this is
also useful because it facilitates writing programs that are “dynamic”
(can change during run time) and that still fully implement Ruby’s
object model. I have heard, though do not really understand, that there
are some problems that are best solved with a dynamic program.

Any comments would be appreciated.

···

On Sunday, March 23, 2003, at 09:14 PM, Greg McIntyre wrote:

Mark Wilson mwilson13@cox.net wrote:

Slide 3, bullet point 1: Ruby is strongly typed (all objects have a
type) and dynamically typed (type is determined at run time).

Hrm… let’s ask the trusty old FOLDOC…

http://foldoc.doc.ic.ac.uk/foldoc/foldoc.cgi?strongly+typed
http://foldoc.doc.ic.ac.uk/foldoc/foldoc.cgi?weakly+typed

It seems Ruby is neither, although there is no definition for “loosely
typed” which I may have invented. :\

Perhaps this is a matter of whose definition you use.

[snip]

“Many” is undisputable.

Gavin

···

On Wednesday, March 26, 2003, 12:05:38 PM, Greg wrote:

  • “nearly all” common C/C++ libraries? I doubt it, although
    I could be wrong

Okay okay. It was a bit of a vague statement deliberately. What do you
suggest I write? Many common C/C++ libraries?

Okay, not to feed the flames too much here, but I figured I may as well
include the entirely personal, qualitative reasons I find Ruby a better
mental fit than Python:

First, I like Ruby’s clear, easily-utilized meta-object protocol. This
shows up in a number of superficial features like dynamically-extensible
classes that pass new methods on to existing instances, but also allows
easy clear metaprogramming at the object, class, or metaclass level.
Python class definitions always seemed much more to be a sort of
template for object creation, esp. with the required ‘self’ parameter
and lack of runtime association b/t method definitions and object method
bindings.

Second, while I initially found the “openness” of Python objects
refreshing (having just run screaming from the Java world), I’ve come to
discover that it actually discourages proper encapsulation of objects,
and makes interfaces more brittle, rather than less. The fact that raw
attribute access is the norm in Python makes it difficult to debug a
number of simple errors (i.e., “obj.goo = 2; […] print obj.foo”), and
encourages direct manipulation of internal object state by other
objects, rather than through accessors and mutators.

The syntactic sugar for creating such get/set methods in Ruby makes them
effectively effortless to include in a class, and insures that future
changes to the internal implementation of the class won’t break code
that uses it, as the change from an assignable attribute to a pair of
get/set methods in Python is difficult to make automatic. (And yes,
before anyone mentions it, I’ve seen the recently-added functionality in
Python 2.2 to create that kind of protected attribute. IIRC, however, it
requires defining a new class that “impersonates” a simple scalar, and
it will be quite a while before the existing body of Python libraries
and applications are updated to use it.)

Finally, the flexibility of the syntax allows for some very interesting
domain-specific language work, like the make replacement and HDL
mentioned recently on this list. Python can easily be extended with
classes and functions for specific domains, but the inflexible syntax,
esp. with its required indentation and parenthesis, basically forces you
to make your DSL look just like Python, or do a full
lexing/parsing/evaluating cycle on a new syntax. With Ruby, much like
with Perl, you have just enough “wiggle room” to create a syntax that
"just works" for some subset of possible uses.

Sorry for the somewhat rambling reply, but I hope that some of it helps.

Lennon

Even better:

File.join(‘dir1’, ‘dir2’, ‘dir3’)

-rich

···

On Thursday, March 20, 2003, at 09:40 PM, Paul Prescod wrote:

Some examples of the benefits of pure OOP. I use “have a nice
day”.split
a fair bit, but Python can do that too so it makes it less enjoyable.
:wink:
[‘dir1’, ‘dir2’, ‘filename’].join(File::Separator) might be a better
example.

import os
print os.sep
/
os.sep.join([“dir1”, “dir2”, “dir3”])
‘dir1/dir2/dir3’
print type(os.sep)
<type ‘str’>

Paul Prescod wrote:

Greg McIntyre wrote:

In Python you can assign function names to variables and then call them
through those variables, however AFAIK this relies on separate function
definitions and global variables in order to achieve the same level of
context manipulation possible with a Ruby block, so it certainly isn’t
as clean and easy.

I’m having trouble following this bit. It’s true that you can’t directly
overwrite a variable in a surrounding context. I don’t know that this
has anything to do with assigning function names to variables or global
variables or anything. The usual workaround is to mutate an object
rather than overwriting a variable.

def a():
state = {}
def putin(x):
state[“something”] = x
def getout(x):
return state[“something”]
return putin, getout

But every example I see of this seems contrived to me. You’re trying to
build a “thing” which has both mutable state and functional behaviour.
Well, in OO languages we tend to call those things objects.

class a:
def putin(self, x):
self.something = x
def getout(self, x):
return self.something

I used to argue that closures were just another way of encapsulating
state and behavior, so a clean OO language would omit them (TOOWTDI).
But I’ve been convinced that closures and objects are two tools that,
used side by side, can really make code more elegant (The Ruby Way, IMO).

Closures can be created on the fly and, since we’re using ruby, we can
use block syntax to do so. This is especially useful for GUI callbacks.
A snippet using an imaginary GUI toolkit:

icon = Icon.new(…)

SliderControl.new(“Horizontal position”) do |new_x|
icon.move_to(new_x, icon.y)
end

Could this be made so elegant in Python?

Seth Kurtzberg seth@cql.com writes:

Ruby has closures, Python does not. Not getting into the “who’s better”
argument; just citing a fact.

Actually, no, that’s wrong. Python has had closures for a while now.

def make_adder(x):
… def adder(y):
… return x + y
… return adder

a10 = make_adder(10)
a10(2)
12

–Johann