Partial Euphoric Type Checking

Greetings all Type Checkers!

I have implemented a version of euphoria’s type system in Ruby.

the good stuff

module Kernel
def typechecking(x=nil)
return $_tc if x == nil
$_tc = x ? true : false
end
end

class Module
def type(tname, &check)
define_method(tname) do |*v|
if $_tc
unless v.all? { |y| check.call(y) }
raise TypeError
end
end
return *v
end
end
end

demonstrate how it feels

class TypeTest
type :big4 do |x|
x > 4
end
def ameth(x)
# – type checking –
big4 x
# – rest of code –
puts x
end
end

typechecking true # turn type checking on
t = TypeTest.new
t.ameth(5) # => 5
t.ameth(2) # => TypeError

Now if you can just get matz to add a little sytax sugar for type and inline parameter methods:

class TypeTest
type big4(x)
x > 4
end
def ameth(big4 x)
puts x
end
end

would that quell the need?

-t0

In some ways, but it’s written in Ruby, and it doesn’t look like it can check
available object methods without slipping in Ruby code to do so. It falls
under the category of “third-party kludge” because it’s doing a job that most
people assume the language implementation itself would provide. I can’t
imagine this would be terribly efficient, either.

Sean O'Dell
···

On Thursday 20 November 2003 12:52 pm, T. Onoma wrote:

Greetings all Type Checkers!

I have implemented a version of euphoria’s type system in Ruby.

the good stuff

module Kernel
def typechecking(x=nil)
return $_tc if x == nil
$_tc = x ? true : false
end
end

class Module
def type(tname, &check)
define_method(tname) do |*v|
if $_tc
unless v.all? { |y| check.call(y) }
raise TypeError
end
end
return *v
end
end
end

demonstrate how it feels

class TypeTest
type :big4 do |x|
x > 4
end
def ameth(x)
# – type checking –
big4 x
# – rest of code –
puts x
end
end

typechecking true # turn type checking on
t = TypeTest.new
t.ameth(5) # => 5
t.ameth(2) # => TypeError

Now if you can just get matz to add a little sytax sugar for type and
inline parameter methods:

class TypeTest
type big4(x)
x > 4
end
def ameth(big4 x)
puts x
end
end

would that quell the need?

In article E1AMvnC-0002fH-T7@odie.runbox.com,

Greetings all Type Checkers!

I have implemented a version of euphoria’s type system in Ruby.

the good stuff

module Kernel
def typechecking(x=nil)
return $_tc if x == nil
$_tc = x ? true : false
end
end

class Module
def type(tname, &check)
define_method(tname) do |*v|
if $_tc
unless v.all? { |y| check.call(y) }
raise TypeError
end
end
return *v
end
end
end

demonstrate how it feels

class TypeTest
type :big4 do |x|
x > 4
end
def ameth(x)
# – type checking –
big4 x
# – rest of code –
puts x
end
end

typechecking true # turn type checking on
t = TypeTest.new
t.ameth(5) # => 5
t.ameth(2) # => TypeError

Now if you can just get matz to add a little sytax sugar for type and
inline parameter methods:

Why does Matz need to add any sugar? You show how it can be done above.
Sure, it would make what you’re trying to do look a little nicer, but why
don’t you just release your code above as a module on the RAA and document
it nicely and then people can use it if they wish (and not use it if they wish).

class TypeTest
type big4(x)
x > 4
end
def ameth(big4 x)
puts x
end
end

would that quell the need?

It’s got it’s uses but I wouldn’t hold my breath for any sugar :wink:

Phil

···

T. Onoma transami@runbox.com wrote:

quack! quack! I added duck typing capability to my euphoric type checking
system:

module Kernel
def typechecking(x=nil)
return $_tc if x == nil
$_tc = x ? true : false
end
end

class Module
def type(tname, *resp, &check)
define_method(tname) do |*v|
if $_tc
unless v.all? { |y| resp.all? { |z| y.send(:respond_to?, z) } }
raise TypeError, "#{v}"
end
unless v.all? { |y| check.call(y) }
raise TypeError, "#{v}"
end
end
return *v
end
end
end

Probabably could be written a little more concise. now example:

type :big4, ‘>’, ‘to_i’, ‘succ’ do |x|
x > 4
end

def ameth(x)
big4 x

···

#—
puts x
end

big4 will make sure parameter responds to #> #to_i and #succ and is also
greater than 4.

i also have a some better ideas for sugar too:

class TypeTest

 type big4(x)
   '>', 'to_i', 'succ'
 unless
   x > 4
 end

 def ameth(big4 x)
   puts x
 end

end

getting better? we may have other clauses besides ‘unless’ too (?) seems like
i’m starting to converge on Sean’s idea from another angle. except mine is
dynamic runtime, but it can be turned offf globally or locally.

BUT!!! i have discovered a problem with all type systems! see next
post…(or 2)

-t0

Now some for some rally crazy cross thought. First a complete interface
definition substantiated on an existent class.

type :IOInteface, *(IO.methods &
IO.private_methods &
IO.protected_methods)

def ameth(x)
IOInterface x

···

#—
x.read
end

now Lets use theoretical duck_signs with euphoria. will we be happy quackers?

type :big4, ‘>’, ‘to_i’, ‘succ’ do |x|
x > 4
end

def ameth(x)
big4 x
#—
puts x.succ
end

method(:ameth).duck_signature # => [ [ ‘succ’ ] ]
method(:big4).duck_signature # => Holy Quack’n Ducks, Batman!

Consider:

def type(tname, *resp, &check)
define_method(tname) do |*v|
if $_tc
unless v.all? { |y| resp.all? { |z| y.send(:respond_to?, z) } }
raise TypeError, "#{v}"
end
unless v.all? { |y| check.call(y) }
raise TypeError, "#{v}"
end
end
return *v
end
end

can it be done?

  1. infinite arity? hmm…have to be considered parameter of array?
  2. conditioned (on global) how to signify signiture is conditional?
  3. respond_to(‘all?’) No, not really array try |y|?
  4. y.send, of course, but means y.respond_to?, of course, but means y.z?
  5. so… ‘>’, ‘to_i’, ‘succ’, i guess?

my head hurts :frowning: i fear godel will soon appear and slap my bitch funny.

BUT wait! There is an even simplier problem!!!..(see next post)

-t0

for some cross rally some thought crazy. ( read: i need a type system for my
email! )

Oh, before i introduce you to a very bad duck, check out the very good duck at
_whyTheLuckyStiff’s home page: http://whytheluckystiff.net/. It’s awesome!

Okay, now the bad duck. Consider this example of my euphoric type system:

class TypeTest

type (:big4, '>', 'to_i', 'succ')

def ameth(x)
  big4 x
···

#—
x > 4
end

end

typechecking true

t = TypeTest.new

t.ameth(5) # => 5 good
t.ameth(4) # => ‘big4’ : 4 (TypeError) good
t.ameth(‘5’) # => `>’: comparison of String with 4 failed (ArgumentError)

bad duck!

you see we have a problem here. it doesn’t matter what methods are
implemented, because ‘>’ for a String and ‘>’ for a Numeric don’t DO
the same KIND OF thing. the operators are overloaded. so respond_to? isn’t
enough. we end up having to think about what will be passed to those
responding methods as well – we end up having to ask not only, can you
handle the responsibilities? but can you handle the arguments? (sounds like a
thread i know :wink:

this problem not only effects my system, by Sean’s as well, which by the way
are not so distinct. we can of course say that it’s GOOD ENOUGH, but some
might say, that’s just quackery. (can you guezz who?)

so while there are good ducks, like _whys, their are also not-so-good ducks.
and ducks in general are not always what their “quacked” up to be, just like
that kind_of? beast.

-t0

you see we have a problem here. it doesn’t matter what methods are
implemented, because ‘>’ for a String and ‘>’ for a Numeric don’t DO
the same KIND OF thing. the operators are overloaded. so respond_to? isn’t
enough. we end up having to think about what will be passed to those
responding methods as well – we end up having to ask not only, can you
handle the responsibilities? but can you handle the arguments? (sounds like a
thread i know :wink:

So we’d like the code we write to tell us when we’ve screwed up, but a typing system is basically not smart enough, because type alone does not determine functionality.

I guess we’re back to unit testing.

Or am I over-simplifying?

···


Chris
http://clabs.org

you see we have a problem here. it doesn’t matter what methods are
implemented, because ‘>’ for a String and ‘>’ for a Numeric don’t DO
the same KIND OF thing. the operators are overloaded. so respond_to? isn’t
enough. we end up having to think about what will be passed to those
responding methods as well – we end up having to ask not only, can you
handle the responsibilities? but can you handle the arguments? (sounds like a
thread i know :wink:

So we’d like the code we write to tell us when we’ve screwed up, but a
typing system is basically not smart enough, because type alone does not
determine functionality.

I guess we’re back to unit testing.

Or am I over-simplifying?

My view is that neither testing for the presence of a method with a
certain name, nor doing that as well as testing for type of the
parameters, is a sufficient type check. Then sin example from the pickaxe
shows this: two methods with exactly the same signature in any aspect you
can measure without delving into the code. Still they do different things.
Even if every method does exactly as it promises, you can’t find out the
promise by looking at method signatures.

Now this was never a problem in a language like Java, because ancestry
told you about the promises a method makes. OK, promises are meant to be
broken, but even in ruby code it’s a problem if a method doesn’t do what
the caller expects it to do. Not that Java is ideal, especially the fact
that types and classes are the same, except for interfaces. There are
languages that have two types of classes: abstract ones, providing a
hierarchy of interfaces, and implementation classes providing an
implementation for a set of interfaces. You can’t inherit from
implementation classes, you can only include its code (mixin-like). This
is full separation of type and class. And implementing an interfaces holds
a promise as to the methods in it. I think it should be doable in Ruby to
have something like that, adapted to ruby’s dynamical context. But it
includes more typing (as in hitting keyboard keys), which is a big
turn-off. But it’s self-documenting, which saves some typing to.

Anyway, I’m not contesting that The Ruby Way works. But nobody showed
evidence that The Ruby Way With Optional Interface Checking doesn’t work
better, though people tried based on flaws of other languages. Ruby is a
dynamic language, but that doesn’t say much about its users. (This is not
an argument, it’s applicable to anything, it’s a punch line).

Peter

The thing that I fear is that the current proposals for Interface
Checking are … going to change Ruby for the worse.

I agree with the comments that immutable interfaces are probably a
Bad Thing, and that’s a core feature of the current proposals.

Why not consider doing interfaces in Ruby as bundles of DbC
“contracts”[1]? That way, you get dynamic interfaces that aren’t
necessarily simplistic name-checks, which is what I’m opposed to.

-austin
[1] Thanks, Eivind, for the term

···

On Fri, 21 Nov 2003 23:53:49 +0900, Peter wrote:

Anyway, I’m not contesting that The Ruby Way works. But nobody
showed evidence that The Ruby Way With Optional Interface Checking
doesn’t work better, though people tried based on flaws of other
languages. Ruby is a dynamic language, but that doesn’t say much
about its users. (This is not an argument, it’s applicable to
anything, it’s a punch line).


austin ziegler * austin@halostatue.ca * Toronto, ON, Canada
software designer * pragmatic programmer * 2003.11.21
* 09.56.54

Peter Peter.Vanbroekhoven@cs.kuleuven.ac.be wrote in message news:Pine.LNX.4.44.0311211531540.23782-100000@merlin.cs.kuleuven.ac.be

Anyway, I’m not contesting that The Ruby Way works. But nobody showed
evidence that The Ruby Way With Optional Interface Checking doesn’t work
better, though people tried based on flaws of other languages.

One problem that I can see is that Optional Interface Check could
impose a significant cost on those who aren’t interested in
type-checking. Primarily, integrating type-checking code with
non-type-checking code could be a burden. I really don’t want to be
browsing through ruby code libraries thinking “is this a type-checked
library?” Or worse, downloading some ruby code only to find that it
didn’t mention that type checking was a core approach of the library.
For these reasons, I think the burden should be on the type-checking
implementors to be able to disable the checking with no or few ill
effects. Hmm, I guess this comment applies slightly more to
interface/inheritance checking systems instead of “method signature”
based systems.

Cheers
-alan

Most libraries only expect native Ruby types or their own types. Rarely do
they expect you to construct a type all by yourself, you’re usually given a
factory method or a class you can call #new on. So even if they did
interface checking, the compliance would already be there for you. Also, it
doesn’t affect your existing code because it’s allowed to live alongside
non-interface-checked code.

Sean O'Dell
···

On Friday 21 November 2003 11:57 am, Alan Chen wrote:

Peter Peter.Vanbroekhoven@cs.kuleuven.ac.be wrote in message
news:Pine.LNX.4.44.0311211531540.23782-100000@merlin.cs.kuleuven.ac.be

Anyway, I’m not contesting that The Ruby Way works. But nobody showed
evidence that The Ruby Way With Optional Interface Checking doesn’t work
better, though people tried based on flaws of other languages.

One problem that I can see is that Optional Interface Check could
impose a significant cost on those who aren’t interested in
type-checking. Primarily, integrating type-checking code with
non-type-checking code could be a burden. I really don’t want to be
browsing through ruby code libraries thinking “is this a type-checked
library?” Or worse, downloading some ruby code only to find that it
didn’t mention that type checking was a core approach of the library.
For these reasons, I think the burden should be on the type-checking
implementors to be able to disable the checking with no or few ill
effects. Hmm, I guess this comment applies slightly more to
interface/inheritance checking systems instead of “method signature”
based systems.

I thought of that earlier when I read Sean’s proposal however I
dismissed it initially because I thought it would be too much effort.
However I think it’s a distinct possibility!

The “Partial Euphoric” type system T. Onoma has put forward seems to be
a little like sets of preconditions tagged with identifiers and later
applied to method paramters.

I see it as a gradient… if you put in no effort, you can have little
typechecking, if you put in a little effort, you can have a bit more,
etc. DbC is way up the deep end of the scale where you put in
substantial effort and receive substantial returns. What’s more, I think
it should be up to the Ruby developer how much checking is desired.

On the effort scale, IMO:

No checking << Duck typing == Interface checking based upon method name

  • arity (“organised duck typing”?) << Interface checking based upon
    method signature == Type checking in static languages << Interface
    checking based upon DbC contracts

(<< means “much more than”)

That’s just my view of the world, maybe DbC isn’t that much effort. It
certainly can give wonderful rewards: very powerful and descriptive
interfaces.

Here’s a wild suggestions. What if all these levels could be
incorporated in Ruby as separate, optional, non-conflicting libraries?
Okay, maybe I should go lie down now. :wink:

···

Austin Ziegler austin@halostatue.ca wrote:

Why not consider doing interfaces in Ruby as bundles of DbC
“contracts”[1]? That way, you get dynamic interfaces that aren’t
necessarily simplistic name-checks, which is what I’m opposed to.


Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://puyo.cjb.net ]===

The thing that I fear is that the current proposals for Interface
Checking are … going to change Ruby for the worse.

I agree with the comments that immutable interfaces are probably a
Bad Thing, and that’s a core feature of the current proposals.

Why not consider doing interfaces in Ruby as bundles of DbC
“contracts”[1]? That way, you get dynamic interfaces that aren’t
necessarily simplistic name-checks, which is what I’m opposed to.

I agree. But I would like to see more coming out of this meanwhile long
thread than just the next impasse. That’s why I’m trying to help Sean a
bit by keeping him on the true ruby path. And maybe we’ve finally got
someone who’s stubborn enough to give it a real try and put interface
checking to the test. If it changes ruby for the better, that great. If it
only does that for some people, and leaves other people untouched, that’s
an addition too. When it changes things for the worse, we can start
arguing again…

Peter

One problem that I can see is that Optional Interface Check could
impose a significant cost on those who aren’t interested in
type-checking. Primarily, integrating type-checking code with
non-type-checking code could be a burden. I really don’t want to be
browsing through ruby code libraries thinking “is this a type-checked
library?” Or worse, downloading some ruby code only to find that it
didn’t mention that type checking was a core approach of the library.
For these reasons, I think the burden should be on the type-checking
implementors to be able to disable the checking with no or few ill
effects. Hmm, I guess this comment applies slightly more to
interface/inheritance checking systems instead of “method signature”
based systems.

As I see it now - for me it is certainly not a settled issue either -
maybe an interface could just give you a convenient way to do respond_to?
checks. And any object could be allowed to “duck type” the interface. But
declaring that a class does implement the interface can serve as
documentation, just like formalizing the respond_to? checks using those
interfaces can. I still like the idea of self-documenting code because
it’s harder to get inconsistent. But for that, it would only work really
well if it was a language feature rather as an extension. Especially
since the only way to disable it such that it becomes overheadless
currently is when it is built in, though a feature like :wrap or :pre
could change that.

Maybe what I’m trying to say is that if duck typing is The Ruby Way, then
it can’t hurt to have some support for that in Ruby. I guess I’m someone
who’s pretty sensitive to the I-have-done-this-before feeling, and when
documenting code or writing unit tests I easily feel like I’m doing
something over and over again when it comes to duck typing - among other
things, but it’s about duck typing now. This feeling is what makes me long
for another language each time I learn a new one. But anyhow, like I said,
if duck typing is The Ruby Way, I feel that including support for that on
more levels than we have now does not limit anything but can save (at
least me) some time because some things happen automatically.

Maybe that’s just me…

Peter

Austin Ziegler wrote:

Why not consider doing interfaces in Ruby as bundles of DbC
“contracts”[1]? That way, you get dynamic interfaces that aren’t
necessarily simplistic name-checks, which is what I’m opposed to.

-austin
[1] Thanks, Eivind, for the term

austin ziegler * austin@halostatue.ca * Toronto, ON, Canada
software designer * pragmatic programmer * 2003.11.21
* 09.56.54

dbc contracts and unit tests are useful features. Nothing now known
will really solve the problem, but those both ameliorate it. Do be
sure, however, that the dbc contracts are only expensive while
debugging. Because they can be quite expensive.

I agree. But I would like to see more coming out of this meanwhile long
thread than just the next impasse. That’s why I’m trying to help Sean a
bit by keeping him on the true ruby path. And maybe we’ve finally got
someone who’s stubborn enough to give it a real try and put interface
checking to the test. If it changes ruby for the better, that great. If it
only does that for some people, and leaves other people untouched, that’s
an addition too. When it changes things for the worse, we can start
arguing again…

Replace that “by keeping him on the true ruby path” by “by trying to keep
him on what I think is the true ruby path a bit more” (I’m a lazy
typist…) Anyway, I’d like it if you’d help me doing that than just pass
judgement on his proposal. I’d like this issue to finally become a bit
clearer to me.

BTW, maybe some other idea… Duck typing is in my opinion the dynamic
equivalent of generics in a statically typed language. Well, at least if
they’d make some decent implementation of it. However in a statically
typed language you need to make the compiler happy with type declarations
while in a dynamically typed language you just need your common sense.
This notion simply extends to duck typing as well. IMO both the static and
the dynamic world are moving in the same general direction. Also for
static languages, unit testing as well as DbC are gaining field, or at
least the academic world, or at least the part of it I know.

Peter