Thoughts on typelessness

Hi –

The on-going discussion of explicit typing and Ruby has whetted my
appetite for traveling further into the typeless universe :slight_smile: But
mainly, it’s got me trying to think fairly deeply and precisely into
the question of why this notion keeps coming back, in spite of its
fairly manifest (and, I think, pretty universally acknowledged)
extrinsicness to Ruby. These comments, then, pertain to typelessness,
and to the question of why some people’s embrace of the Ruby model is
equivocal. (They’re not specific to the ‘R’ initiative, though
obviously that’s been at the center of recent debate.)

There’s a scene in Buster Keaton’s film “Sherlock, Jr.” where Keaton
is on an out-of-control motorcycle, about to come to a huge gap
between two stretches of elevated road – i.e., he’s about to plummet.
But two trucks come along on the road underneath, from opposite
directions, and converge for just an instant in precisely such a way
that Keaton can glide across their tops and onto the road on the other
side of the gap. A second earlier or a second later, he would indeed
have plummeted – but for just that instant, the necessary components
were in place.

Ruby objects remind me of that scene. They are what they are at a
given moment, whether or not that’s what they were or what they will
be. And in their momentary permutations and capabilities, they can do
some very powerful things.

All of this is so enthralling to me that I’m always surprised when
people advocate explicit typing (in one form or another) for Ruby. It
seems that, in spite of everything (including the existence of other
languages for those made queasy by typelessness), a number of Ruby
users are more drawn to type-based programming than away from it. I
wonder why this is.

I don’t have a particular or conclusive answer, just some thoughts.
Mainly these have to do with Ruby methods and syntax, rather than
other factors (like whether managers will accept a dynamically typed
language).

One possible factor, I think, is the #type method. As I mentioned on
IRC this evening, I sometimes wish Ruby didn’t have it. It’s harder
to make the argument that objects don’t have types, when the objects
themselves willingly tell you their types… :slight_smile: And I might add
#is_a? and #kind_of? to the list. Maybe they’re necessary for
reflection. It’s interesting to try to program without them.

Another thing people often point to that might deter people from
learning a truly type-unchecked programming style is the wordiness of
the most often-mentioned alternative, the “respond_to?” test:

thing.action if thing.respond_to?(action)

This has the look and feel of duplicate, workaround code. Whereas
this:

raise ArgumentError unless obj.is_a?(Thing)

doesn’t, and neither does this:

case obj
when /String/ …
when /Array/ …

(And of course this:

def meth(String s)

wouldn’t either :slight_smile:

So one problem might be that while the focus is on what an object will
respond to, the #respond_to? test itself is by no means the most
concise or elegant available idiom. This means that testing for type
offers a path of less resistance – so people take it.

(Of course, in looking at behavior in Ruby as fundamentally per-object
and dynamic, testing with #respond_to? isn’t conclusive anyway, since
the response in question may or may not be what one wants. But it’s
on the right path, because it’s addressing the present of the object,
not its past.)

You can also do this:

begin
a.meth
rescue NameError

I’ve done that, for instance, in my dbdbd (database definer) program.
It uses 1-originating array notation to index columns, but can also
use field-names. So the reader method for the sort_key (for example)
is:

def sort_key
@sort_key - 1
rescue NameError
@sort_key
end

which I think looks better than:

def sort_key
if @sort_key.respond_to?(:slight_smile:
@sort_key - 1
else
@sort_key
end
end

or any of the many variants of that. But the rescue version is
relatively slow.

There’s also been talk of a sort of conditional method call, where the
call would only happen if the object responds to the method. The
problem with that is: what happens if it fails? You can’t just return
nil or false, since those might be what the successful method call
would have returned.

I don’t have any conclusive, ummm, conclusions to draw. Just
wondering what people think of all of this. There was talk briefly of
the idea of multi-dispatch and method signatures on respond_to?
criteria, rather than type. Maybe that’s a way to bring that more
accessibly and concisely into the syntax. (Though I’m not sure
exactly what that way would consist of, syntactially.)

David

···


David Alan Black | Register for RubyConf 2002!
home: dblack@candle.superlink.net | November 1-3
work: blackdav@shu.edu | Seattle, WA, USA
Web: http://pirate.shu.edu/~blackdav | http://www.rubyconf.com

Hi David,

Your exposition is very wide and deep. I will try to respond to just one
part of it:

dblack@candle.superlink.net wrote:

All of this is so enthralling to me that I’m always surprised when
people advocate explicit typing (in one form or another) for Ruby. It
seems that, in spite of everything (including the existence of other
languages for those made queasy by typelessness), a number of Ruby
users are more drawn to type-based programming than away from it. I
wonder why this is.

In a “statically typed” language (such as C), variables have types, while
data do not. In a “dynamically typed” language (such as Ruby), variables
do not have types, while data do. You see, we always need some “type”,
but the problem is usually where to put it. If variables have types, then
the compiler/interpreter works harder by keeping track of them, but the
data representation in the memory is more efficient: int is “always” 4
bytes in a memory location somewhere, and double is “always” 8 bytes in a
memory location somewhere (well, “always” means for a particular
machine/os.)

When variables are typeless such as in Ruby, then the types should be
stored in the data themselves. A Float is not only 8 bytes of memory. A
Float has to contain some bytes to signify its type. When gc is presence,
than a Float datum also has to contain either a reference count or a mark
bit. (Ruby is pretty good in this respect, that it has minimized all
those extra bits and bytes per object.) Nonetheless, I think this is
true: in general, a statically typed language will have smaller memory
print than a dynamically typed language.

When variables have types, then it is possible to access data using
memory offset (which a computer will gladly do for us) rather than
using a hash function (in which a computer has to perform multiple extra
steps). So I think this is also true: for a given task, while the Ruby
code is probably 2 - 10 times shorter than a corresponding C code, the
net computer instructions run by the Ruby code is probably 2 - 10 times
more than that of the corresponding C code.

I think Ruby is so far the best from the programmer’s point of view, while
C (we exclude assembly for now) is the best from the computer’s point of
view. Well, we all are programmers, so we love Ruby. But when my
computer does not give me my desired result in 10 hours, then I have to
take care of my computer also so that it can give me the result in 1 hour
instead. So far, the solution is to convert the core to C while leaving
the peripherals and interfaces in Ruby, similar in spirit to what Alan
Chen has mentioned.

Now, the question is, have we fully examined the design space between Ruby
and C? If we come out with a language that is 50% the easiness of Ruby
and 50% of the performance of C, I don’t think there is any useful
effort. However, if it turns out that we can create something that is 80%
the easiness of Ruby and at the same time 80% the performance of C, I
think we really can call that a progress.

When we examine the design space between C and Ruby, then usually
static/dynamic typing is the first thing to come to mind, as these two
languages are exactly at the opposite spectrum in this respect. And of
course, then all those discussions (such as R) follow…

Finally, it is true that for purely numerical computations, a solution
such as Ruby’s NArray suffices, because basically we need only integers,
floats, and arrays, and they are usually static during the whole process
(which sometimes may take hours or even days). However, a network
simulation is entirely different, as we do need struct’s/objects, and some
of those objects are highly dynamic (such as communication packets) while
some are really static (such as network nodes and links). I have used a
commercial software which is totally based on C, and it is relatively
fast, but it takes so long to develop and test new protocols and
algorithms. That’s why I am exploring Ruby. So far the programming
experience has been extremely great, but the resulting code performance is
not so. That’s why I am thinking other possibilities…

Regards,

Bill

Good words, David. My responses are interleaved below.

Hi –

The on-going discussion of explicit typing and Ruby has whetted my
appetite for traveling further into the typeless universe :slight_smile: But
mainly, it’s got me trying to think fairly deeply and precisely into
the question of why this notion keeps coming back, in spite of its
fairly manifest (and, I think, pretty universally acknowledged)
extrinsicness to Ruby. These comments, then, pertain to typelessness,
and to the question of why some people’s embrace of the Ruby model is
equivocal. (They’re not specific to the ‘R’ initiative, though
obviously that’s been at the center of recent debate.)

Some people feel safer with explicit types. There are good subjective reasons
for this:

  • computing should be explicit
  • you need greater rigidity as projects get large
  • most people have a backgound in explicit typing, and those
    languages have explicit types for good reason

In university, one of the core things I learned in first-year computer science
was “abstract data types” - learning to understand and implement lists, trees,
hashes, etc. This is obviously important to know, and it implies the
importance of strong types, and knowing what you’re dealing with.

There’s a scene in Buster Keaton’s film “Sherlock, Jr.” where Keaton
is on an out-of-control motorcycle, about to come to a huge gap
between two stretches of elevated road – i.e., he’s about to plummet.
But two trucks come along on the road underneath, from opposite
directions, and converge for just an instant in precisely such a way
that Keaton can glide across their tops and onto the road on the other
side of the gap. A second earlier or a second later, he would indeed
have plummeted – but for just that instant, the necessary components
were in place.

Ruby objects remind me of that scene. They are what they are at a
given moment, whether or not that’s what they were or what they will
be. And in their momentary permutations and capabilities, they can do
some very powerful things.

And they can just miss the trucks, plummet to the road below, break their arms
and legs, and then get run over by the truck. Then they get sent to hell
instead of heaven because some SOB redefined their finalizer.

Building projects that even potentially rely on trucks coming together can be
described in the following ways: creative, interesting, risky, irresponsible,
crazy, brilliant.

All of this is so enthralling to me that I’m always surprised when
people advocate explicit typing (in one form or another) for Ruby. It
seems that, in spite of everything (including the existence of other
languages for those made queasy by typelessness), a number of Ruby
users are more drawn to type-based programming than away from it. I
wonder why this is.

The fundamental reason I hear most often is the desire to weed out bugs at
compile-time, not run-time. This will be argued by many on the list, myself
included, as something of a fallacy. However, these arguments tend to rely on
the primacy of unit testing, rather than proving correct designs. There is
nothing necessarily right ot wrong about this, but it is inconsistent with what
we learnt, and came to agree with, at university. (I don’t know what unis
teach nowadays.) Most of us, at some point, have to ask whether Ruby really
concurs with what we think is “right”. I’d be interested to know if and how
you traversed these crossroads, David.

One thing’s for sure: “dynamic programming” leaves a lot of risk at run-time.
It is a matter of continuing debate how much of this risk can be ameliorated.
As I’ve said before, Ruby is an experiment, like non-Euclidean geometry. Dave
Thomas exhorts those with queasy stomachs to try writing seriously large Ruby
applications and seeing if their fears materialise.

Ruby introduces (to my radar, at least - I’m sure Smalltalkers will disagree) a
new paradigm for programming. As this gains greater acceptance, traditional
academics will have to focus some research efforts on it. By the looks of it,
Ruby can ride the wave of interest in XP, and maybe benefot from research into
that, but that’s only have the story.

Until such research is carried out, and time allowed for the flow-on effects
(articles, education, …) we are bound to have the same debates time and
again. Every day, someone new is having to ask themselves whether and how to
embrace a “typeless” language.

I’d like to see, as a crystallisation of discussions on this list, a document
prepared outlining the costs and benefits of Ruvy programming. Something to
make very interesting reading for Java programmers. Of course, I’m not putting
my hand up, and do not have the necessary experience anyway.

I don’t have a particular or conclusive answer, just some thoughts.
Mainly these have to do with Ruby methods and syntax, rather than
other factors (like whether managers will accept a dynamically typed
language).

One possible factor, I think, is the #type method. As I mentioned on
IRC this evening, I sometimes wish Ruby didn’t have it. It’s harder
to make the argument that objects don’t have types, when the objects
themselves willingly tell you their types… :slight_smile: And I might add
#is_a? and #kind_of? to the list. Maybe they’re necessary for
reflection. It’s interesting to try to program without them.

You should try to program without them, but it may not always be impossible or
undesirable. (To suggest this is surely to place yourself near a far end of
the spectrum in this debate, David.)

I think types will always be important in computer programming. Anyone care to
disagree? The problem we have in Ruby is how to define them. They’re so hard
to pin down. Ruby still has cookie-cutters (classes), but both the
cookie-cutters and the resulting cookies can grow new arms and new legs,
meaning that neither of them is wholly suitable for defining something as
significant and universal as a “type”. You put it best, Davis when you said
that a Ruby object is what it is.

However, in practical programming (remember that? :wink: it is sometimes important
to know what you’re dealing with. It is somethimes desirable to allow a method
to act on either an Array or Hash or String or …, and exhibit sensible but
different behaviour based on this. The writer of the method thus assumes:

  • you will not overly distort the class Array, String, …
  • you will not overly distort objects of said classes
  • you will want to use objects of these classes rather than objects
    of some other class that is vaguely similar to an Array, for instance

These assumptions generally hold true for the important built-in classes like
Array and String. They will start to break down when you define and distort
your own objects. Therefore, a blurry line can be drawn where such code as
“case x when Array …” etc. starts to become poor programming.

Another thing people often point to that might deter people from
learning a truly type-unchecked programming style is the wordiness of
the most often-mentioned alternative, the “respond_to?” test:

thing.action if thing.respond_to?(action)

This has the look and feel of duplicate, workaround code. Whereas
this:

raise ArgumentError unless obj.is_a?(Thing)

doesn’t, and neither does this:

case obj
when /String/ …
when /Array/ …

(And of course this:

def meth(String s)

wouldn’t either :slight_smile:

So one problem might be that while the focus is on what an object will
respond to, the #respond_to? test itself is by no means the most
concise or elegant available idiom. This means that testing for type
offers a path of less resistance – so people take it.

The price of liberty is eternal vigilance. This applies to Ruby programming
(and especially design) as much as it does walking alone at night in large
American cities. People have to decide what balance they want to achieve
between order and chaos in Ruby programs, and then they have to enforce it.
(This is the heart of the typeless debate.)

Asking an object if it responds to :xyz is deeply unsatisfying. Even if it
does, you have no idea what that method will do. The English language is full
of homonyms, so Ruby objects have the potential to be as well.

Therefore, querying the class of an object not only is the path of least
resistance, it gives you more assurance of what you’re actually dealing with.
It may be a blunt instrument, and one may have reservations about using it, but
in some situations its all we have.

Raising ArgumentError is a way to ensure that you get a sensible error message.
A common complaint is that unwelcome objects make their way deep into methods
before their identity is finally uncovered by dint of not responding to a
method. If you are somehow undure of your code, it’s better to find this out
sooner rather than later.

Also, consider this. If you do raise ArgumentError because an object is the
“wrong” “type”, and later find this is unnecessarily restraining you, you can
liberalise the method later. The point is, you’ll easily find out. If you’d
been liberal in the first place, you may have suffered a cryptic error. In
Ruby, it’s easy to build walls and break them down as needed.

(Of course, in looking at behavior in Ruby as fundamentally per-object
and dynamic, testing with #respond_to? isn’t conclusive anyway, since
the response in question may or may not be what one wants. But it’s
on the right path, because it’s addressing the present of the object,
not its past.)

You can also do this:

begin
a.meth
rescue NameError

I’ve done that, for instance, in my dbdbd (database definer) program.
It uses 1-originating array notation to index columns, but can also
use field-names. So the reader method for the sort_key (for example)
is:

def sort_key
@sort_key - 1
rescue NameError
@sort_key
end

which I think looks better than:

def sort_key
if @sort_key.respond_to?(:slight_smile:
@sort_key - 1
else
@sort_key
end
end

or any of the many variants of that. But the rescue version is
relatively slow.

It does look better. But what if the object responds to :- but doesn’t do what
you want. If you’re lucky, your program wil break cleanly. Otherwise, you’ll
end up with funny indexing of critical data committed to a file. I’m only
playing devil’s advocate here.

There’s also been talk of a sort of conditional method call, where the
call would only happen if the object responds to the method. The
problem with that is: what happens if it fails? You can’t just return
nil or false, since those might be what the successful method call
would have returned.

I don’t have any conclusive, ummm, conclusions to draw. Just
wondering what people think of all of this. There was talk briefly of
the idea of multi-dispatch and method signatures on respond_to?
criteria, rather than type. Maybe that’s a way to bring that more
accessibly and concisely into the syntax. (Though I’m not sure
exactly what that way would consist of, syntactially.)

I don’t support the method dispatch stuff, and side with you on most aspects of
this issue. To me, the dispatch stuff is too wordy for to little return. I’m
not passionate in opposition to it, though; it could be useful, but it could
change the language somehow, and cause people to write lots of ugly code.

David


David Alan Black | Register for RubyConf 2002!

Gavin

···

----- Original Message -----
From: dblack@candle.superlink.net

I don't have any conclusive, ummm, conclusions to draw. Just
wondering what people think of all of this. There was talk briefly of
the idea of multi-dispatch and method signatures on respond_to?
criteria, rather than type. Maybe that's a way to bring that more
accessibly and concisely into the syntax. (Though I'm not sure
exactly what that way would consist of, syntactially.)

Why do you think that I've added module in the signature (see
(ruby-talk:50139)) ?

an enumerable is just an object which respond to #each

pigeon% cat b.rb
#!./ruby
class A
   def tt(Enumerable a)
      p "I respond to #each : #{a.inspect}"
   end

   def tt(Kernel a)
      p "I don't know #each : #{a.inspect}"
   end
end

a = A.new
a.tt([1, 2])
a.tt("string")
a.tt(A.new)

pigeon%

pigeon% b.rb
"I respond to #each : [1, 2]"
"I respond to #each : \"string\""
"I don't know #each : #<A:0x401ad360>"
pigeon%

Guy Decoux

dblack@candle.superlink.net wrote in message
news:Pine.LNX.4.44.0209282304250.5063-100000@candle.superlink.net

There’s a scene in Buster Keaton’s film “Sherlock, Jr.” where Keaton

side of the gap. A second earlier or a second later, he would indeed
have plummeted – but for just that instant, the necessary components
were in place.

Ruby objects remind me of that scene. They are what they are at a
given moment, whether or not that’s what they were or what they will
be. And in their momentary permutations and capabilities, they can do
some very powerful things.

This also very much indicate the fragility of the method.
I don’t believe Ruby objects are so fragile in praxis and I think we should
not focus too hard on Rubys extreme dynamism (don’t do it just because you
can).
The great thing about Ruby is that you can easily replace a file class with
a string class and still have many read operations work the same way -
without having to first carefully design an interface.

All of this is so enthralling to me that I’m always surprised when
people advocate explicit typing (in one form or another) for Ruby. It
seems that, in spite of everything (including the existence of other
languages for those made queasy by typelessness), a number of Ruby
users are more drawn to type-based programming than away from it. I
wonder why this is.

There are many reasons - the major misguided reason is compile time checking
(although spelling mistakes is a problem in Ruby). Most errors are not type
errors and most type errors are due to the type constraints and would not a
an issue in a language like Ruby.

So why would people like types: Personally I like the Ruby syntax and spirit
but also realize that most code do not expose and great dependency on
extreme dynamism - why shouldn’t we be able to compile this efficiently? Yes
there are other languages - but please suggest one you’d like to use. There
are not that many to choose from although I would mention OCaml as one.
However OCaml syntax and concepts are rather different from Ruby.

Mikkel

Another thing people often point to that might deter people from
learning a truly type-unchecked programming style is the wordiness of
the most often-mentioned alternative, the “respond_to?” test:

thing.action if thing.respond_to?(action)

Do you really want your method to go on even if thing' doesn't respond to action’? Similarly, would you do the following?

thing.action if thing.is_a?(Thing)

That would look as redundant (and dangerous).

This has the look and feel of duplicate, workaround code. Whereas
this:

raise ArgumentError unless obj.is_a?(Thing)

Sorry David, I feel you’re comparing apples and oranges here. :slight_smile:

I don’t think `thing.action if thing.respond_to?(action)’ is a likely
case. The following would:

raise ArgumentError unless thing.respond_to?(action)
thing.action

Which as you can see is just symmetric to:

raise ArgumentError unless obj.is_a?(Thing)
thing.action

the #respond_to? test itself is by no means the most concise or
elegant available idiom.

If verbs were always chosen for method names, this could be nice:

obj.can?(:mkdir)

And this wouldn’t be too bad:

def meth(obj)
  continue if
    obj.can?(:mkdir) and
obj.can?(:recurse) and
obj.can?(:list)

Or more concise:

def meth(obj)
  continue if obj.can?(:mkdir, :recurse, :list)

Massimiliano (bard on IRC)

···

On Sun, Sep 29, 2002 at 12:09:32PM +0900, dblack@candle.superlink.net wrote:

dblack@candle.superlink.net wrote:

Hi –

I don’t have any conclusive, ummm, conclusions to draw. Just
wondering what people think of all of this. There was talk briefly of

If you create only objects and extend them, you can test
the pros and cons.

Find below the “Hello typeless world!” script:

def new
Object.new
end

module A
def foo
print “Hello”
end

def to_s
“typeless”
end
end

module B
def baz(x)
puts " #{x} world!\n"
end
end

x = new
y = new

x.extend A
y.extend B

x.foo
y.baz(x)

etc,etc…

Just curious… Is there a strongly typed language that does NOT have the
equivalent of casts and void pointers?

(lots of interesting remarks about explicit typing discussion)

One possible factor, I think, is the #type method. As I mentioned on
IRC this evening, I sometimes wish Ruby didn’t have it. It’s harder
to make the argument that objects don’t have types, when the objects
themselves willingly tell you their types… :slight_smile: And I might add
#is_a? and #kind_of? to the list. Maybe they’re necessary for
reflection. It’s interesting to try to program without them.

(snip)

I’ve done that, for instance, in my dbdbd (database definer) program.
It uses 1-originating array notation to index columns, but can also
use field-names. So the reader method for the sort_key (for example)
is:

def sort_key
@sort_key - 1
rescue NameError
@sort_key
end

When you announced dbdbd I quickly browsed through the code. I
had the impression that I understood your well written program -
besides this very example. I really tried to understand what’s going
on, but I just couldn’t get it.

which I think looks better than:

def sort_key
if @sort_key.respond_to?(:slight_smile:
@sort_key - 1
else
@sort_key
end
end

Ok. With this alternative code and the remarks in your mail I finally
understand what you did. But for me the most intention revealing
implementation would simply be:

def sort_key
if @sort_key.is_a? Integer
@sort_key - 1
else
@sort_key
end
end

I’m sure it would be very interesting to try to program without #type,
#is_a? etc and I’m sure I will try to do so in the future, but for me
this wasn’t a good example. If you think so, too, maybe you could
find an other implementation. I’d be very interested in what you’d
come up with.

Regards,
Pit

···

On 29 Sep 2002, at 12:09, dblack@candle.superlink.net wrote:

I the NameError acutally might be thrown inside @sort_key.- , because
of an programming error e.g., not because the the method does not exist.
So you must at least check for Exepction.backtrace.size == 1.

-billy.

···

On Sun, Sep 29, 2002 at 12:09:32PM +0900, dblack@candle.superlink.net wrote:

You can also do this:

begin
a.meth
rescue NameError

I’ve done that, for instance, in my dbdbd (database definer) program.
It uses 1-originating array notation to index columns, but can also
use field-names. So the reader method for the sort_key (for example)
is:

def sort_key
@sort_key - 1
rescue NameError
@sort_key
end

which I think looks better than:

def sort_key
if @sort_key.respond_to?(:slight_smile:
@sort_key - 1
else
@sort_key
end
end

or any of the many variants of that. But the rescue version is
relatively slow.


Meisterbohne Söflinger Straße 100 Tel: +49-731-399 499-0
eLösungen 89077 Ulm Fax: +49-731-399 499-9

Mon, 30 Sep 2002 07:15:09 +0900, Albert Wagner alwagner@tcac.net pisze:

Just curious… Is there a strongly typed language that does NOT
have the equivalent of casts and void pointers?

Depending on what you mean by “have” (do non-standard library
facilities count if they aren’t needed in 99% of programs?)
Haskell, OCaml, SML have expressive, static, safe type systems
without casts and void pointers.

···


__("< Marcin Kowalczyk
__/ qrczak@knm.org.pl
^^ Blog człowieka poczciwego.

I’m not sure I disagree, and being a self-taught programmer who is just
now, little by little, learning computer science theory, I don’t have
much basis for an original contribution to this debate. But I’ve been
following a long-running and bitter (yet nonetheless substantive and
extremely well-informed) debate on the xml-dev list over the merits of
static data types in W3C XML Schema. And one of the arguments I’ve seen
against static typing, goes something like: static types tie programmers
hands, yet leave the really hard problems unsolved–the really hard
problems being mainly related to ensuring that objects/variables have
appropriate values. It made a lot of sense to me, at least for the kind
of rigid and opaque type system found in languages like C, C++, and
Java.

But it seems to me that more sophisticated approaches like Eiffel’s
contracts and Haskell’s pattern-based types go a long way toward
addressing that shortcoming.

···

On Sun, Sep 29, 2002 at 02:29:33PM +0900, Gavin Sinclair wrote:

I think types will always be important in computer programming. Anyone care to
disagree?


Matt Gushee
Englewood, Colorado, USA
mgushee@havenrock.com

  • computing should be explicit

Computers require explicit instructions. Humans aren’t necessarily
computers – or, if we are, we operate at a level much more complex than
physical computing machines.

  • you need greater rigidity as projects get large

I think this is a false belief. If I weren’t illiterate, I’d reference
published materials that assert this. But, alas, I’m illiterate.

  • most people have a backgound in explicit typing, and those
    languages have explicit types for good reason

“One hundred thousand lemmings can’t be wrong.”

The fundamental reason I hear most often is the desire to weed out bugs at
compile-time, not run-time.

Compile-time doesn’t affect the end-user. Only run-time affects the end
user. So, focus on program correctness at run-time.

The belief is that if you can eliminate a subset of all possible errors
at compile-time, that reduces the search space of errors that you need
to check for at run-time. I make the claim that if you properly ensure
correctness at run-time, you will also cover all errors that can be
determined at compile-time, so checking for errors at compile-time is
redundant.

One thing’s for sure: “dynamic programming” leaves a lot of risk at run-time.

All programming leaves lots of risk at run-time. Dynamic vs. static
typed languages simply leave different risks.

I think types will always be important in computer programming.
Anyone care to disagree?

I think the notion of abilities will be important in computer
programming. Programs having abilities, or objects having abilities, or
agents having abilities, etc.

We have a tendency to classify things into types in order to make sense
of the world around us. However, in a world of similar patterns that
form types, typing at the level of granularity of the whole object is
too rough. It needs to be at the level of the abilities that make up
the object.

Perhaps it is because of these things that makes the concept of
polymorphism so difficult to grasp … I’m not sure.

– Dossy

···

On 2002.09.29, Gavin Sinclair gsinclair@soyabean.com.au wrote:


Dossy Shiobara mail: dossy@panoptic.com
Panoptic Computer Network web: http://www.panoptic.com/
“He realized the fastest way to change is to laugh at your own
folly – then you can let go and quickly move on.” (p. 70)

I don’t have any conclusive, ummm, conclusions to draw. Just
wondering what people think of all of this. There was talk briefly of
the idea of multi-dispatch and method signatures on respond_to?
criteria, rather than type. Maybe that’s a way to bring that more
accessibly and concisely into the syntax. (Though I’m not sure
exactly what that way would consist of, syntactially.)

Why do you think that I’ve added module in the signature (see
(ruby-talk:50139)) ?

an enumerable is just an object which respond to #each

This is questionable; depends what you mean. An Enumerable also responds to
:grep, :sort, etc., according to ‘ri’.

And “class X; def each end; end” responds to “each”, but is not Enumerable.

And of course, you can “include Enumerable” without even implementing #each!

And you can take an Enumerable object (say, anArray) and undefine #each.

What becomes of your method signatures in all these cases?

[code, though interesting, snipped]

Guy Decoux

Gavin

···

----- Original Message -----
From: “ts” decoux@moulon.inra.fr

Sun, 29 Sep 2002 15:14:19 +0900, Dossy dossy@panoptic.com pisze:

The belief is that if you can eliminate a subset of all possible
errors at compile-time, that reduces the search space of errors
that you need to check for at run-time. I make the claim that if
you properly ensure correctness at run-time, you will also cover
all errors that can be determined at compile-time, so checking for
errors at compile-time is redundant.

You might as well say that exceptions are a redundant mechanism
because you might just return some garbage or nil and find the error
during testing.

The question is how easy is to find the actual error basing on the
diagnostic. In my experience static typing makes it much easier,
especially when you change something in a working program and want
to update all places which depend on the change.

Yes, it does have some costs (that static type systems aren’t
expressive enough and the most expressive ones like Haskell’s are
also the most complicated). Neither static nor dynamic typing is
always better than the other.

But we use dynamically typed languages despite static types make
finding errors easier, because we value other aspects more. Not
because they don’t make it easier.

···


__("< Marcin Kowalczyk
__/ qrczak@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/

Hi –

Another thing people often point to that might deter people from
learning a truly type-unchecked programming style is the wordiness of
the most often-mentioned alternative, the “respond_to?” test:

thing.action if thing.respond_to?(action)

Do you really want your method to go on even if thing' doesn't respond to action’? Similarly, would you do the following?

thing.action if thing.is_a?(Thing)

That would look as redundant (and dangerous).

This has the look and feel of duplicate, workaround code. Whereas
this:

raise ArgumentError unless obj.is_a?(Thing)

Sorry David, I feel you’re comparing apples and oranges here. :slight_smile:

Yes, I don’t think all my examples are synonymous with each other.

If verbs were always chosen for method names, this could be nice:

obj.can?(:mkdir)

And this wouldn’t be too bad:

def meth(obj)
  continue if
    obj.can?(:mkdir) and

obj.can?(:recurse) and
obj.can?(:list)

Or more concise:

def meth(obj)
  continue if obj.can?(:mkdir, :recurse, :list)

I don’t think the verb thing is a necessity. Maybe I’m just being
influenced by the “Ich kann Deutsch” (“I can [speak] German”) idiom.
Actually this is all reminiscent of Franz Schubert’s stock question,
upon being introduced to or told about another person: “Kann er was?”
(Can he do anything? i.e., is he good at anything?) :slight_smile:

Anyway, just for fun, here’s a little testbed. Ummmm, it just got
less little. It expands modules and classes into their public
instance methods, so you can do obj.can?(Enumerable).

module Kernel
def can?(*meths)
x_meths = meths.map do |m|
begin
m.public_instance_methods
rescue NameError
m
end
end .flatten
not x_meths.detect { |m| not respond_to?(m) }
end

def screen_for(*meths)
  if can?(*meths)
    yield
    true
  else
    false
  end
end

end

class CanTest
def meth(obj)
raise NameError unless obj.can?(:split, :chomp)
obj.split(//)
end

def screen_me(obj)
  obj.screen_for(:split, :chomp) do
    puts "OK, passed the screen"
    obj.split(//)
  end
end

def screen_for_Enum(obj)
  obj.screen_for(Enumerable) do
    puts "OK, passed the Enum screen"
    obj.each {|e| puts "Element: #{e}"}
  end
end

end

c = CanTest.new
puts c.meth(“abc”)
begin puts c.meth(); rescue NameError; puts “Didn’t work with ”;
end

puts c.screen_me(“abc”)
puts c.screen_for_Enum([1,2,3])
puts c.screen_for_Enum(3)

David

···

On Sun, 29 Sep 2002, Massimiliano Mirra wrote:

On Sun, Sep 29, 2002 at 12:09:32PM +0900, dblack@candle.superlink.net wrote:


David Alan Black | Register for RubyConf 2002!
home: dblack@candle.superlink.net | November 1-3
work: blackdav@shu.edu | Seattle, WA, USA
Web: http://pirate.shu.edu/~blackdav | http://www.rubyconf.com

“ts” wrote

I don’t have any conclusive, ummm, conclusions to draw. Just
wondering what people think of all of this. There was talk briefly of
the idea of multi-dispatch and method signatures on respond_to?
criteria, rather than type. Maybe that’s a way to bring that more
accessibly and concisely into the syntax. (Though I’m not sure
exactly what that way would consist of, syntactially.)

Why do you think that I’ve added module in the signature (see
(ruby-talk:50139)) ?

You answered this yourself already - to kill the whole idea;-)

/Christoph

Massimiliano Mirra wrote:

If verbs were always chosen for method names, this could be nice:

obj.can?(:mkdir)

And this wouldn’t be too bad:

def meth(obj)
continue if
obj.can?(:mkdir) and
obj.can?(:recurse) and
obj.can?(:list)

Or more concise:

def meth(obj)
continue if obj.can?(:mkdir, :recurse, :list)

That’s interesting and I like it. With a little tweaking it should be
able to provide nice runtime diagnostics about what object was passed
where, how it was defined, and why it failed. That’s usefull, because
in some of my Ruby projects I have mistakenly passed the wrong object to
the wrong function, and then of course things would blow up. I’d have
to hunt the problem down, and that wasn’t always easy. This would
provide a little extra layer of insulation.

BUT…

I’m still not sure this really solves the problem (it only helps
diagnose it better). The core problem really isn’t guaranteeing you can
perform an operation on an object. Instead, it’s guaranteeing that an
object conforms to a specification before we let it loose to wreak havoc
in the dynamic Ruby environment.

Here is an example:

Let’s say I write a library, and I have an extension point within my
library. You can write your own object and add it in as an extension to
my library, as long as it conforms to certain conventions (i.e.
implements certain functions with specific behaviors). Now, you, the
library user don’t fully understand the scope of what you are doing and
goof up one of the functions. Depending on your program and the
library, it’s quite possible this function may rarely get called. You
can spend hours, days, weeks, months assuming there is no problem and
everything works correctly. Then one day, another user comes along with
a slightly different configuration than yours and boom everything blows
up in your face.

Of course, you COULD check for this using Unit Tests. But can you
guarantee that the end user will use unit tests and use them properly?
I would hazard a guess and say no, of course not. I like to write
libraries that make it as hard as possible for the user to shoot
themselves in the foot, because I know from experience that MOST
programmers (at least out of those I have worked with or gone to school
with) out there just don’t have the skillset I do and WILL screw
things up long before I will, so it’s usually up to me to prevent that
from happening.

What can you do about this? I just wrote up a whole proposal for a
contract interface, but then I deleted it because I’m not sure of the
ramifications of an upfront contract/interface implementation and Ruby’s
ability to dynamically add methods to a class. So my real question is…

Why doesn’t Ruby have some sort of Contract/Interface specification (ala
Java Interfaces or Eiffel Contracts)? Is there a technical reason that
these aren’t possible, or is it just a subject that has not been
properly approached yet? I’ve seen lots of discussion about static
types and responds_to? method, but I think both of these are really just
one small aspect of the much larger problem: guaranteeing up front that
the library user implements the required functionality.

Bryan

Now, the question is, have we fully examined the design space between
Ruby
and C? If we come out with a language that is 50% the easiness of Ruby
and 50% of the performance of C, I don’t think there is any useful
effort. However, if it turns out that we can create something that is
80%
the easiness of Ruby and at the same time 80% the performance of C, I
think we really can call that a progress.

What about ObjC? Seems intuitively to be about 60-70% of the easiness
and 80% of the performance.

When we examine the design space between C and Ruby, then usually
static/dynamic typing is the first thing to come to mind, as these two
languages are exactly at the opposite spectrum in this respect. And of
course, then all those discussions (such as R) follow…

Interesting that ObjC opted for optional static typing.

···

On Saturday, September 28, 2002, at 09:50 PM, William Djaja Tjokroaminata wrote:

We are all born originals - why is it so many of us die copies?
-Edward Young, poet (1683-1765)

Hi –

def sort_key
@sort_key - 1
rescue NameError
@sort_key
end

When you announced dbdbd I quickly browsed through the code. I
had the impression that I understood your well written program -
besides this very example. I really tried to understand what’s going
on, but I just couldn’t get it.

Whoops :slight_smile:

def sort_key
if @sort_key.is_a? Integer
@sort_key - 1
else
@sort_key
end
end

I’m sure it would be very interesting to try to program without #type,
#is_a? etc and I’m sure I will try to do so in the future, but for me
this wasn’t a good example. If you think so, too, maybe you could
find an other implementation. I’d be very interested in what you’d
come up with.

One direction one can go in – probably heavy overkill for this
example, but anyway – is extending the capacity of objects.

module MinusStub
def -(val)
self
end
end

class Thing
def sort_key
@sort_key - 1
end

def sort_key=(val)
  @sort_key = val
  @sort_key.extend(MinusStub) unless @sort_key.respond_to?(:-)
end

end

if FILE == $0
t = Thing.new
t.sort_key = 5
p t.sort_key # 4
p t.sort_key * 10 # 40
t.sort_key = “Hello”
p t.sort_key # “Hello”
end

(I know there are some issues about this approach to maintaining a
simultaneously 0- and 1-originating array… but I won’t go into all
of that here :slight_smile:

I actually really like Massimiliano’s #can? idea:

@sort_key.extend(MinusStub) unless @sort_key.can?(:slight_smile:

looks nice to me, and slightly more abstracted (in a good way, I
think) than respond_to?

David

···

On Mon, 30 Sep 2002, Pit Capitain wrote:

On 29 Sep 2002, at 12:09, dblack@candle.superlink.net wrote:


David Alan Black | Register for RubyConf 2002!
home: dblack@candle.superlink.net | November 1-3
work: blackdav@shu.edu | Seattle, WA, USA
Web: http://pirate.shu.edu/~blackdav | http://www.rubyconf.com