"stereotyping" (was: Re: Strong Typing (Re: Managing metadata about attribute types)

But again, that flexibility is LOST when you have to pass an
object to a method that REQUIRES it to behave a certain way.

Using “kind_of” testing /further/ reduces flexibility by requiring
particular inheritance structures in addition to the protocol requirements.

Having absolutely NO mechanism leaves people who need to check
for certain methods and parameters hanging in the wind.

Can you give an example of where someone would NEED to check.

···


– Jim Weirich / Compuware
– FWP Capture Services
– Phone: 859-386-8855

But again, that flexibility is LOST when you have to pass an
object to a method that REQUIRES it to behave a certain way.

Using “kind_of” testing /further/ reduces flexibility by requiring
particular inheritance structures in addition to the protocol requirements.

No, the flexibility is gone already; kind_of? just provides a more informative
way to find out what went wrong.

Having absolutely NO mechanism leaves people who need to check
for certain methods and parameters hanging in the wind.

Can you give an example of where someone would NEED to check.

Okay, you got it. Here’s an example of how this sort of type checking would
be useful:

I am the developer of a web server library. I have written a library which
contains a class that is used as the server-end of an HTTP request. It is
essentially a socket that I use to read and write.

Now, Bob the application developer decides to use my library to write himself
a little HTTP applet. He writes a CGI method that hooks into my library and
when he runs the applet, he can pass form data to the server and his little
CGI hook does something fun.

But Bob’s CGI method is not working as intended, so he decides to do some
debugging.

He decides to build the full HTTP request as a text file, and pipe the file to
the CGI method through my library by opening it with the File object and
passing a File object where I was expecting a Socket object.

The code goes BOOM. The library is trying to make calls to methods that don’t
exist. Bob sees what methods are being requested, but he has no reference to
them. Nowhere does he see “I expected a Socket.” It’s just not there. The
calls are being made, but what are they? What interface does my library
want? He has no clue. All he sees are error messages, but since he is not
me, he doesn’t know I expected a Socket object. It’s never declared
anywhere.

Now, let’s add in interface checking.

My methods all require that objects being passed in declare themselves with
the Socket interface signature.

Now replay the scenario.

Bob gets a message “that object does not implement the Socket interface.”

Bob knows what went wrong. He looks up the Socket interface, modifies his
File object to fake the interface and provide my library with all the
read/write functions it expects, with a full reference to what parameters are
expected and so on.

This is not a complicated scenario, either. I would wager that some people
monitoring this newsgroup have actually tried to do this at some point in
their programming career, perhaps even tried it with Ruby.

Getting an error message that an object is of the type required, is VERY
useful in some places. Not always, but in some places.

Sean O'Dell
···

On Wednesday 19 November 2003 11:47 am, Weirich, James wrote:

Can you give an example of where someone would NEED to check.
Okay, you got it. Here’s an example of how this sort of type checking
would
be useful:
[…]

He decides to build the full HTTP request as a text file, and pipe the
file to the CGI method through my library by opening it with the File
object and passing a File object where I was expecting a Socket object.

irb(main):002:0> require ‘socket’
=> true
irb(main):003:0> Socket.ancestors
=> [Socket, BasicSocket, IO, File::Constants, Enumerable, Object, Kernel]
irb(main):004:0> File.ancestors
=> [File, IO, File::Constants, Enumerable, Object, Kernel]
irb(main):005:0> Socket.methods - File.methods
=> [“pack_sockaddr_in”, “do_not_reverse_lookup”, “getservbyname”,
“do_not_reverse_lookup=”, “unpack_sockaddr_in”, “socketpair”,
“gethostbyname”, “getaddrinfo”, “pair”, “getnameinfo”, “gethostname”,
“sockaddr_in”, “gethostbyaddr”]
irb(main):006:0> Socket.instance_methods - File.instance_methods
=> [“bind”, “sysaccept”, “recvfrom”, “accept”, “listen”, “connect”]

Aside from the above methods, as long as your HTTP server doesn’t depend on
those items in the place where Bob would send the request (you have
designed
your code with appropriate separation of concerns, haven’t you?), then I see
no problem.

The code goes BOOM. The library is trying to make calls to methods that
don’t exist. Bob sees what methods are being requested, but he has no
reference to them. Nowhere does he see “I expected a Socket.”

Since Bob is a smart programmer, he’ll see in his error log:

NoMethodError: undefined method `accept’ for #<File:3>
from …

Well, this means that his File object doesn’t know the method #accept.
Therefore, he can open the source to your HTTP library and see “oh! this
guy’s
expecting a Socket and has put accept in the wrong place!” If Bob’s a really
smart programmer, he’d already know that #accept is a Socket method.

I’ve found bugs in libraries and bugs in my own code – with the software
working just as it does already. Your scenario doesn’t stand.

-austin

···

On Thu, 20 Nov 2003 05:17:10 +0900, Sean O’Dell wrote:

On Wednesday 19 November 2003 11:47 am, Weirich, James wrote:

austin ziegler * austin@halostatue.ca * Toronto, ON, Canada
software designer * pragmatic programmer * 2003.11.19
* 16.13.28

Can you give an example of where someone would NEED to check.

Okay, you got it. Here’s an example of how this sort of type checking

would

be useful:

[…]

He decides to build the full HTTP request as a text file, and pipe the
file to the CGI method through my library by opening it with the File
object and passing a File object where I was expecting a Socket object.

irb(main):002:0> require ‘socket’
=> true
irb(main):003:0> Socket.ancestors
=> [Socket, BasicSocket, IO, File::Constants, Enumerable, Object, Kernel]
irb(main):004:0> File.ancestors
=> [File, IO, File::Constants, Enumerable, Object, Kernel]
irb(main):005:0> Socket.methods - File.methods
=> [“pack_sockaddr_in”, “do_not_reverse_lookup”, “getservbyname”,
“do_not_reverse_lookup=”, “unpack_sockaddr_in”, “socketpair”,
“gethostbyname”, “getaddrinfo”, “pair”, “getnameinfo”, “gethostname”,
“sockaddr_in”, “gethostbyaddr”]
irb(main):006:0> Socket.instance_methods - File.instance_methods
=> [“bind”, “sysaccept”, “recvfrom”, “accept”, “listen”, “connect”]

Aside from the above methods, as long as your HTTP server doesn’t depend on
those items in the place where Bob would send the request (you have
designed
your code with appropriate separation of concerns, haven’t you?), then I
see no problem.

The code goes BOOM. The library is trying to make calls to methods that
don’t exist. Bob sees what methods are being requested, but he has no
reference to them. Nowhere does he see “I expected a Socket.”

Since Bob is a smart programmer, he’ll see in his error log:

NoMethodError: undefined method `accept’ for #<File:3>
from …

Well, this means that his File object doesn’t know the method #accept.
Therefore, he can open the source to your HTTP library and see “oh! this
guy’s
expecting a Socket and has put accept in the wrong place!” If Bob’s a
really smart programmer, he’d already know that #accept is a Socket method.

Wrong! There’s no mention of the Socket object anywhere! The only way he
would know that is by searching the source code of OTHER METHODS that call
that method, then tracing back to where the object that is passed in was
created. Then he can see Socket.new.

Also, don’t make the assumption that the developer automatically knows #accept
belongs to the Socket object. Your familiarity with Socket is causing you to
discount the pain a developer feels when this sort of error occurs. A
developer may know NOTHING about the Socket object and will not have a CLUE
about #accept.

I’ve found bugs in libraries and bugs in my own code – with the software
working just as it does already. Your scenario doesn’t stand.

Sure it does.

Sean O'Dell
···

On Wednesday 19 November 2003 01:25 pm, Austin Ziegler wrote:

On Thu, 20 Nov 2003 05:17:10 +0900, Sean O’Dell wrote:

On Wednesday 19 November 2003 11:47 am, Weirich, James wrote:

Since Bob is a smart programmer, he’ll see in his error log:

NoMethodError: undefined method `accept’ for #<File:3> from …

Well, this means that his File object doesn’t know the method
#accept. Therefore, he can open the source to your HTTP library
and see “oh! this guy’s expecting a Socket and has put accept in
the wrong place!” If Bob’s a really smart programmer, he’d
already know that #accept is a Socket method.
Wrong! There’s no mention of the Socket object anywhere! The only
way he would know that is by searching the source code of OTHER
METHODS that call that method, then tracing back to where the
object that is passed in was created. Then he can see Socket.new.

Not really. Since Ruby is open source, he can add a quick debug
print:

def foo(arg)
$STDERR.puts arg.inspect
:
:
end

He runs the library normally and he’ll see that the incoming
argument is a Socket. But there’s also a neat

The other point that I’ll make is that I’ve had to deal with very
similar debugging mechanisms in C, C++, and PL/SQL.

Also, don’t make the assumption that the developer automatically
knows #accept belongs to the Socket object. Your familiarity with
Socket is causing you to discount the pain a developer feels when
this sort of error occurs. A developer may know NOTHING about the
Socket object and will not have a CLUE about #accept.

I’m actually not that familiar with Socket at all. I just did what
any Ruby developer can do in irb and discovered that Socket knows
about #accept.

-austin

···

On Thu, 20 Nov 2003 06:32:00 +0900, Sean O’Dell wrote:

On Wednesday 19 November 2003 01:25 pm, Austin Ziegler wrote:

austin ziegler * austin@halostatue.ca * Toronto, ON, Canada
software designer * pragmatic programmer * 2003.11.19
* 19.21.09

Since Bob is a smart programmer, he’ll see in his error log:

NoMethodError: undefined method `accept’ for #<File:3> from …

Well, this means that his File object doesn’t know the method
#accept. Therefore, he can open the source to your HTTP library
and see “oh! this guy’s expecting a Socket and has put accept in
the wrong place!” If Bob’s a really smart programmer, he’d
already know that #accept is a Socket method.

Wrong! There’s no mention of the Socket object anywhere! The only
way he would know that is by searching the source code of OTHER
METHODS that call that method, then tracing back to where the
object that is passed in was created. Then he can see Socket.new.

Not really. Since Ruby is open source, he can add a quick debug
print:

def foo(arg)
$STDERR.puts arg.inspect

end

He runs the library normally and he’ll see that the incoming
argument is a Socket. But there’s also a neat

Not if it was installed as root and he’s not root.

The other point that I’ll make is that I’ve had to deal with very
similar debugging mechanisms in C, C++, and PL/SQL.

Also, don’t make the assumption that the developer automatically
knows #accept belongs to the Socket object. Your familiarity with
Socket is causing you to discount the pain a developer feels when
this sort of error occurs. A developer may know NOTHING about the
Socket object and will not have a CLUE about #accept.

I’m actually not that familiar with Socket at all. I just did what
any Ruby developer can do in irb and discovered that Socket knows
about #accept.

How did you do that without knowing it was Socket to begin with? Armed only
with the knowledge that the error was a call to #accept, how did you deduce
it was the Socket object the method expected?

Sean O'Dell
···

On Wednesday 19 November 2003 04:21 pm, Austin Ziegler wrote:

On Thu, 20 Nov 2003 06:32:00 +0900, Sean O’Dell wrote:

On Wednesday 19 November 2003 01:25 pm, Austin Ziegler wrote: