caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Re: OCAML Downcasting?
       [not found] ` <ci9ggm$i6p$1@wolfberry.srv.cs.cmu.edu>
@ 2004-09-21  8:03   ` Jacques GARRIGUE
  2004-09-21  8:43     ` Damien Pous
  2004-09-21 19:27     ` Michael Vanier
  0 siblings, 2 replies; 29+ messages in thread
From: Jacques GARRIGUE @ 2004-09-21  8:03 UTC (permalink / raw)
  To: caml-list

Reposted from comp.lang.ml:

Matthias Kretschmer <mccratch@gmx.net> writes:

> Roy Patrick Tan schrieb:
>
> > I'm trying to learn about ocaml's object-oriented features. It seems
> > like you can coerce an object of one type to a supertype, but not from
> > a supertype to a subtype. But what if I need to recover the original
> > type?
> 
> I am a bit curious why it is that unsafe that it is completely 
> forbidden. Of course type-checks can't be done at elaboration time and 
> have to be postponed to the evaluation time, but most other OO-languages 
> just implement this and if it is impossible, they raise an exception or 
> abort the program. At least something like Oberon's WITH-statement would 
> sometimes be very handy.

There are two important differences between ocaml and other
OO-languages that have downcasting.

- inheritance is not subtyping. The subtyping relation being
  structural, a full fledge typecast would not only require to keep
  type information at runtime, but to embark a large part of the
  compiler to check subtyping. This might also be incredibly slow.

  As a result, downcast is only reasonable when we have both
  inheritance and subtyping. You're suddenly losing a large part of
  the language.

  Worse, even if you have a module interface
     class b :
       object
         inherit a
         ....
       end
  in ocaml this does _not_ mean that b inherits from a, just that it
  has at least a's methods and fields.
  So the semantics of downcast would not allow abstraction.

- classes may have type parameters. Assume a situation like
    class ['a] a = object ... end
  Then we cannot downcast any runtime object to "a", because we don't
  know what is its type parameter. Again, downcast would not mix well
  with other features of the language.

So, while this is somehow unfortunate, there is no downcast in ocaml.

There are various ways to simulate it, but at first this is a bit
confusing for people used to languages with reflection.

> On the other hand, one can overcome this by using sum-types: e.g. You 
> know about button widgets and label widgets. Of course there can be 
> other widgets, so we have 3 different types to distinguish:
> - buttons
> - labels
> - others
> =>
> type mywidget = Button of button_widget
>                | Label of label_widget
>                | Other of widget

This is indeed the standard way to do it, as it mixes best with a
functional programming language.

> In some circumstances this is nice, because you can simply use pattern 
> matching to extract the type you want. On the other hand, when defining 
> this type you have to know excactly what types you want to handle. So it 
> might get very ugly and clumsy.

Phrased this way, this sounds like you have no way to modify the above
type when you need to add a new subtype.
The straightforward thing to do is to use your editor and add a new
case to the above list. Then the compiler will tell you all the places
you need to modify to take this new case into consideration --
something most OO compilers wouldn't bother to tell you: they would
force you to have a default case, which may be relevant or not, and
you would only discover this at runtime.

For the more special cases where you can't modify the original code,
there are still various ways to simulate downcast, from keeping
objects in hashtables to advanced uses of parametric polymorphism.

Just for fun, here is an example of the second approach:

class virtual ['a] widget = object
  method virtual raw : 'a
end

class ['a] button = object (self)
  inherit ['a] widget
  method raw = `Button self
  method press = prerr_endline "pressed"
end

class ['a] label = object (self)
  inherit ['a] widget
  method raw = `Label self
  val mutable text = ""
  method set_text s = text <- s
end

let l = [(new button :> _ widget); (new label :> _ widget)]

let f = function
    `Button b -> b#press
  | `Label l -> l#set_text "Hello" 

let test () =
  List.iter (fun o -> f o#raw) l

Such a programming pattern lets you use downcasting in a refined way,
without any language support. It even avoids the first limitation I
described above (label need not really inherit from widget). But the
fact you must keep 'a polymorphic makes it advanced.

Jacques Garrigue

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [Caml-list] Re: OCAML Downcasting?
  2004-09-21  8:03   ` [Caml-list] Re: OCAML Downcasting? Jacques GARRIGUE
@ 2004-09-21  8:43     ` Damien Pous
  2004-09-21  9:15       ` Jacques GARRIGUE
  2004-09-21 19:27     ` Michael Vanier
  1 sibling, 1 reply; 29+ messages in thread
From: Damien Pous @ 2004-09-21  8:43 UTC (permalink / raw)
  To: caml-list

Hello,

Jacques GARRIGUE <garrigue@kurims.kyoto-u.ac.jp> wrote:
> Just for fun, here is an example of the second approach:
> 
> class virtual ['a] widget = object
>   method virtual raw : 'a
> end 
> class ['a] button = object (self)
>   inherit ['a] widget
>   method raw = `Button self
>   method press = prerr_endline "pressed"
> end

How to write a signature for this code ?

even "ocamlc -i" fails ! 

<<
#ocamlc -i error.ml
class virtual ['a] widget : object method virtual raw : 'a end
class ['a] button :
  object ('b)
    constraint 'a = [> `Button of 'b ]
    method press : unit
    method raw : 'a
  end
>>

then 
<<
#ocamlc -c error.ml
The implementation error.ml does not match the interface error.cmi:
Class declarations do not match:
  class ['a] button :
    object ('b)
      constraint 'a = [> `Button of 'b ]
      method press : unit
      method raw : 'a
    end
does not match
  class ['a] button :
    object
      constraint 'a = [> `Button of 'a button ]
      method press : unit
      method raw : 'a
    end
One type parameter has type
  [> `Button of < press : unit; raw : 'a; .. > as 'b ] as 'a
but is expected to have type [> `Button of 'c button ] as 'c
Type 'b is not compatible with type 'c button = < press : unit; raw : 'c >
>>

thanks,
Damien

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21  8:43     ` Damien Pous
@ 2004-09-21  9:15       ` Jacques GARRIGUE
  2004-09-21  9:29         ` skaller
  2004-09-21  9:34         ` Stefano Zacchiroli
  0 siblings, 2 replies; 29+ messages in thread
From: Jacques GARRIGUE @ 2004-09-21  9:15 UTC (permalink / raw)
  To: Damien.Pous; +Cc: caml-list

From: Damien Pous <Damien.Pous@ens-lyon.fr>

> Jacques GARRIGUE <garrigue@kurims.kyoto-u.ac.jp> wrote:
> > Just for fun, here is an example of the second approach:
> > 
> > class virtual ['a] widget = object
> >   method virtual raw : 'a
> > end 
> > class ['a] button = object (self)
> >   inherit ['a] widget
> >   method raw = `Button self
> >   method press = prerr_endline "pressed"
> > end
> 
> How to write a signature for this code ?
> 
> even "ocamlc -i" fails ! 

You're right.
I shall never post before verifying my code seriously.
The real code is:

class virtual ['a] widget = object
  method virtual raw : 'a
end

class ['a] button = object (self)
  inherit ['a] widget
  method raw = `Button (self :> 'a button)
  method press = prerr_endline "pressed"
end

class ['a] label = object (self)
  inherit ['a] widget
  method raw = `Label (self :> 'a label)
  val mutable text = ""
  method set_text s = text <- s
end

let l = [(new button :> _ widget); (new label :> _ widget)]

let f = function
    `Button b -> b#press
  | `Label l -> l#set_text "Hello" 

let test () =
  List.iter (fun o -> f o#raw) l

Without the self-cast, you cannot extend any class.

Jacques Garrigue

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21  9:15       ` Jacques GARRIGUE
@ 2004-09-21  9:29         ` skaller
  2004-09-21  9:49           ` Jacques GARRIGUE
  2004-09-21  9:34         ` Stefano Zacchiroli
  1 sibling, 1 reply; 29+ messages in thread
From: skaller @ 2004-09-21  9:29 UTC (permalink / raw)
  To: Jacques GARRIGUE; +Cc: Damien.Pous, caml-list

On Tue, 2004-09-21 at 19:15, Jacques GARRIGUE wrote:

> class ['a] button = object (self)
>   inherit ['a] widget
>   method raw = `Button (self :> 'a button)
>   method press = prerr_endline "pressed"
> end

> Without the self-cast, you cannot extend any class.

Is that an issue with classes or polymorphic variants?

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21  9:15       ` Jacques GARRIGUE
  2004-09-21  9:29         ` skaller
@ 2004-09-21  9:34         ` Stefano Zacchiroli
  2004-09-21  9:56           ` Jacques GARRIGUE
  1 sibling, 1 reply; 29+ messages in thread
From: Stefano Zacchiroli @ 2004-09-21  9:34 UTC (permalink / raw)
  To: caml-list

On Tue, Sep 21, 2004 at 06:15:31PM +0900, Jacques GARRIGUE wrote:
> > even "ocamlc -i" fails ! 
> You're right.

Anyway, shouldn't this be considered an "ocamlc -i" bug?

I used to assume that:

  ocamlc -i a.ml > a.mli
  ocamlc -c a.mli
  ocamlc -c a.ml

should work for every compilable a.ml. Was I wrong?

-- 
Stefano Zacchiroli -*- Computer Science PhD student @ Uny Bologna, Italy
zack@{cs.unibo.it,debian.org,bononia.it} -%- http://www.bononia.it/zack/
If there's any real truth it's that the entire multidimensional infinity
of the Universe is almost certainly being run by a bunch of maniacs. -!-

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21  9:29         ` skaller
@ 2004-09-21  9:49           ` Jacques GARRIGUE
  0 siblings, 0 replies; 29+ messages in thread
From: Jacques GARRIGUE @ 2004-09-21  9:49 UTC (permalink / raw)
  To: skaller; +Cc: caml-list

From: skaller <skaller@users.sourceforge.net>
> On Tue, 2004-09-21 at 19:15, Jacques GARRIGUE wrote:
> 
> > class ['a] button = object (self)
> >   inherit ['a] widget
> >   method raw = `Button (self :> 'a button)
> >   method press = prerr_endline "pressed"
> > end
> 
> > Without the self-cast, you cannot extend any class.
> 
> Is that an issue with classes or polymorphic variants?

With classes.
If you omit the coercion, any class inheriting from button would have
the type of the raw method specialized to itself, and as a result it
would be incompatible with button.

...
But strangely enough, some tests show that this is not the case. Even
without the coercion, the type of `Button becomes fixed to 'a button.
Looks like there is a bug in the interaction between classes and
variants. So do not forget the coercion even if it works now
without...

Jacques Garrigue

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21  9:34         ` Stefano Zacchiroli
@ 2004-09-21  9:56           ` Jacques GARRIGUE
  0 siblings, 0 replies; 29+ messages in thread
From: Jacques GARRIGUE @ 2004-09-21  9:56 UTC (permalink / raw)
  To: zack; +Cc: caml-list

From: Stefano Zacchiroli <zack@bononia.it>

> On Tue, Sep 21, 2004 at 06:15:31PM +0900, Jacques GARRIGUE wrote:
> > > even "ocamlc -i" fails ! 
> > You're right.
> 
> Anyway, shouldn't this be considered an "ocamlc -i" bug?
> 
> I used to assume that:
> 
>   ocamlc -i a.ml > a.mli
>   ocamlc -c a.mli
>   ocamlc -c a.ml
> 
> should work for every compilable a.ml. Was I wrong?

This is intended to be so, eventhough this is not always easy to print
a type both exactly and concisely...
In the present case, there clearly seems to be a bug, independently of
the error in the example.

Jacques Garrigue

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21  8:03   ` [Caml-list] Re: OCAML Downcasting? Jacques GARRIGUE
  2004-09-21  8:43     ` Damien Pous
@ 2004-09-21 19:27     ` Michael Vanier
  2004-09-21 21:38       ` Brian Hurt
  2004-09-22  1:30       ` Jacques GARRIGUE
  1 sibling, 2 replies; 29+ messages in thread
From: Michael Vanier @ 2004-09-21 19:27 UTC (permalink / raw)
  To: garrigue; +Cc: caml-list


> Date: Tue, 21 Sep 2004 17:03:39 +0900 (JST)
> From: Jacques GARRIGUE <garrigue@kurims.kyoto-u.ac.jp>
> 
> There are two important differences between ocaml and other
> OO-languages that have downcasting.
> 
> - inheritance is not subtyping. The subtyping relation being
>   structural, a full fledge typecast would not only require to keep
>   type information at runtime, but to embark a large part of the
>   compiler to check subtyping. This might also be incredibly slow.
> 
>   As a result, downcast is only reasonable when we have both
>   inheritance and subtyping. You're suddenly losing a large part of
>   the language.

But java has interfaces (subtypes), and classes can implement interfaces
(making them subtypes of the interface) without inheritance.  Furthermore,
the class identity can be retrieved from an instance of an interface by
using the instanceof operator.

> 
>   Worse, even if you have a module interface
>      class b :
>        object
>          inherit a
>          ....
>        end
>   in ocaml this does _not_ mean that b inherits from a, just that it
>   has at least a's methods and fields.
>   So the semantics of downcast would not allow abstraction.

I don't understand the point you're trying to make here, but it seems like
a is effectively equivalent to an interface in java (at least from your
description).

> - classes may have type parameters. Assume a situation like
>     class ['a] a = object ... end
>   Then we cannot downcast any runtime object to "a", because we don't
>   know what is its type parameter. Again, downcast would not mix well
>   with other features of the language.

Java now has generics (type parameters), and I assume that it has to get
around this situation somehow.

> 
> So, while this is somehow unfortunate, there is no downcast in ocaml.
> 

I'm sure there are good reasons for this, but I don't find the arguments
you've presented above persuasive.  Not that I'm trying to hold java up as
a shining example of the Right Thing; I'd much rather program in ocaml than
java any day of the week.  But the lack of downcasting has frustrated me in
the past (it's my #1 gripe about ocaml, with the lack of support for
native-code shared libraries at #2).

Mike

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21 19:27     ` Michael Vanier
@ 2004-09-21 21:38       ` Brian Hurt
  2004-09-21 22:06         ` Michael Vanier
                           ` (2 more replies)
  2004-09-22  1:30       ` Jacques GARRIGUE
  1 sibling, 3 replies; 29+ messages in thread
From: Brian Hurt @ 2004-09-21 21:38 UTC (permalink / raw)
  To: Michael Vanier; +Cc: garrigue, caml-list

On Tue, 21 Sep 2004, Michael Vanier wrote:

> But java has interfaces (subtypes), and classes can implement interfaces
> (making them subtypes of the interface) without inheritance.  Furthermore,
> the class identity can be retrieved from an instance of an interface by
> using the instanceof operator.

Java also has run time type identification, something Ocaml doesn't have.  
And generally doesn't need.  Downcasting, however, requires RTTI- I hand 
you an object of class foo, you think it's really an object of class bar 
(which inherits from foo), and want to turn the foo into a bar- but how do 
you know it's *really* a bar?  It might just be a foo, it might be a baz 
(a different class inheriting from foo).

The general solution is to rethink the problem to avoid the downcast.  
Some general platitudes: first, avoid upcasts.  Try using column types 
instead.  Second, move the operations that need the downcast into the 
object itself- delegate (the object knows what sort of object it really 
is, even if you don't).  Third, ditch objects.  Java, C++, etc. strongly 
encourage you to think of everything as an object, try designing the code 
sans objects and see how it works.  Fourth, hand implement RTTI- either by 
adding member functions to the base class to do the conversion (throwing 
an exception if the conversion is bad), or using a variant type.

> > - classes may have type parameters. Assume a situation like
> >     class ['a] a = object ... end
> >   Then we cannot downcast any runtime object to "a", because we don't
> >   know what is its type parameter. Again, downcast would not mix well
> >   with other features of the language.
> 
> Java now has generics (type parameters), and I assume that it has to get
> around this situation somehow.

If I understand it correctly, they basically lifted C++'s templates more 
or less verbatim.  I don't have experience with Java Generics, but C++ 
templates create a whole new copy of the class for every type they handle.  
So that List<short>, List<int>, List<float>, List<foo_t>, etc. all use 
different instantiations.  How C++ gets around it is that if you have a 
template<class t> class foo_t, bar_t doesn't so much inherit from foo_t, 
as bar_t<int> inherits from foo_t<int>, etc.

> 
> > 
> > So, while this is somehow unfortunate, there is no downcast in ocaml.
> > 
> 
> I'm sure there are good reasons for this, but I don't find the arguments
> you've presented above persuasive.  Not that I'm trying to hold java up as
> a shining example of the Right Thing; I'd much rather program in ocaml than
> java any day of the week.  But the lack of downcasting has frustrated me in
> the past (it's my #1 gripe about ocaml, with the lack of support for
> native-code shared libraries at #2).

Downcasting is a sign you're doing something wrong.  If you knew the 
object was a bar_t, why didn't it have the type bar_t from the get-go?  If 
you don't know it's a bar_t, how do you know it's safe to cast it to a 
bar_t?  Without RTTI, that is.

By the way, RTTI costs memory (at least one extra word per object, plus 
the overhead of the Class classes for all types).  Plus- does RTTI apply 
to non-objects?  Ocaml has a lot of types that are not classes.

-- 
"Usenet is like a herd of performing elephants with diarrhea -- massive,
difficult to redirect, awe-inspiring, entertaining, and a source of
mind-boggling amounts of excrement when you least expect it."
                                - Gene Spafford 
Brian

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21 21:38       ` Brian Hurt
@ 2004-09-21 22:06         ` Michael Vanier
  2004-09-21 22:32           ` Brian Hurt
  2004-09-22  1:04           ` skaller
  2004-09-21 22:20         ` Marcin 'Qrczak' Kowalczyk
  2004-09-22  0:50         ` skaller
  2 siblings, 2 replies; 29+ messages in thread
From: Michael Vanier @ 2004-09-21 22:06 UTC (permalink / raw)
  To: bhurt; +Cc: caml-list

> Date: Tue, 21 Sep 2004 16:38:25 -0500 (CDT)
> From: Brian Hurt <bhurt@spnz.org>
> Cc: garrigue@kurims.kyoto-u.ac.jp, <caml-list@inria.fr>
> 
> On Tue, 21 Sep 2004, Michael Vanier wrote:
> 
> > But java has interfaces (subtypes), and classes can implement interfaces
> > (making them subtypes of the interface) without inheritance.  Furthermore,
> > the class identity can be retrieved from an instance of an interface by
> > using the instanceof operator.
> 
> Java also has run time type identification, something Ocaml doesn't have.  
> And generally doesn't need.  Downcasting, however, requires RTTI- I hand 
> you an object of class foo, you think it's really an object of class bar 
> (which inherits from foo), and want to turn the foo into a bar- but how do 
> you know it's *really* a bar?  It might just be a foo, it might be a baz 
> (a different class inheriting from foo).

Yes, I was assuming RTTI, which is what the instanceof operator provides.

> > Java now has generics (type parameters), and I assume that it has to get
> > around this situation somehow.
> 
> If I understand it correctly, they basically lifted C++'s templates more 
> or less verbatim.  I don't have experience with Java Generics, but C++ 
> templates create a whole new copy of the class for every type they handle.  
> So that List<short>, List<int>, List<float>, List<foo_t>, etc. all use 
> different instantiations.  How C++ gets around it is that if you have a 
> template<class t> class foo_t, bar_t doesn't so much inherit from foo_t, 
> as bar_t<int> inherits from foo_t<int>, etc.

Um, no, they didn't.  In fact, it's a completely different mechanism.  The
compiler erases the generic information so that the JVM sees only old-style
java classes without parameterization and adds casts where needed.  OK,
this wasn't the greatest example in the world, because it relies massively
on RTTI.

> > > 
> > > So, while this is somehow unfortunate, there is no downcast in ocaml.
> > > 
> > 
> > I'm sure there are good reasons for this, but I don't find the arguments
> > you've presented above persuasive.  Not that I'm trying to hold java up as
> > a shining example of the Right Thing; I'd much rather program in ocaml than
> > java any day of the week.  But the lack of downcasting has frustrated me in
> > the past (it's my #1 gripe about ocaml, with the lack of support for
> > native-code shared libraries at #2).
> 
> Downcasting is a sign you're doing something wrong.  If you knew the 
> object was a bar_t, why didn't it have the type bar_t from the get-go?  If 
> you don't know it's a bar_t, how do you know it's safe to cast it to a 
> bar_t?  Without RTTI, that is.

I don't agree.  For instance, try implementing the equivalent of
multimethods without some kind of downcast.  Of course, if a language
supported multimethods from the get-go it would be even nicer, but very few
languages do.  Now, if you're going to argue that wanting multimethods at
all is a sign that you haven't thought through a problem carefully enough,
we'll just have to agree to disagree.  I'm always suspicious of arguments
that start off with "you really don't want to do that", because I can't say
with any certainty what I will want to do or need to do 100% of the time.

Mike


-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21 21:38       ` Brian Hurt
  2004-09-21 22:06         ` Michael Vanier
@ 2004-09-21 22:20         ` Marcin 'Qrczak' Kowalczyk
  2004-09-22  2:26           ` skaller
  2004-09-22  0:50         ` skaller
  2 siblings, 1 reply; 29+ messages in thread
From: Marcin 'Qrczak' Kowalczyk @ 2004-09-21 22:20 UTC (permalink / raw)
  To: Brian Hurt; +Cc: Michael Vanier, garrigue, caml-list

Brian Hurt <bhurt@spnz.org> writes:

> The general solution is to rethink the problem to avoid the downcast.

It's not always possible or desirable.

Example 1: exceptions. Fortunately OCaml provides an extensible exn
type. It's probably impossible to emulate using other features:
classes, polymorphic variants, modules etc., without Obj.magic.
OTOH dynamically typed or OO languages typically don't need extra
language features just to *represent* exceptions of extensible types.

Example 2: embedding a dynamically typed sublanguage in OCaml, with
extensible set of types of wrapped objects. For this I had to use
Obj.magic with manual tagging of dynamic types.

Attempts to avoid downcasts are often unmodular, they require to
specify all possible variants in one place.

>> Java now has generics (type parameters), and I assume that it has to get
>> around this situation somehow.
>
> If I understand it correctly, they basically lifted C++'s templates more 
> or less verbatim.

AFAIK the implementation technique is entirely different, similar to
parametric polymorphism in OCaml. It influences the semantics. You
can't select overloaded methods basing on a type substituted for a
type variable for example (except by using reflection at runtime);
you can do that in C++. There are no specializations of generics.
There are no types depending on types (an equivalent of putting
different typedefs in different specializations of a template).

Java generics compared to C++ templates are like OCaml parametric
polymorphism compared to OCaml modules.

> Downcasting is a sign you're doing something wrong.

I disagree. It may be, or not. Just that OCaml doesn't support
something doesn't imply that it must be evil.

> If you knew the object was a bar_t, why didn't it have the type
> bar_t from the get-go?

For the same reason as why can't exn be a regular algebraic type.

> If you don't know it's a bar_t, how do you know it's safe to cast it
> to a bar_t? Without RTTI, that is.

Of course something is necessary to determine at runtime whether it's
safe. I don't advocate unsafe constructs.

> By the way, RTTI costs memory (at least one extra word per object,
> plus the overhead of the Class classes for all types).

You could move the object header there. It would only make no room for
two bits for GC that OCaml uses, so it would be hard to adapt to OCaml
as it is, but it's not a significant overhead in general.

A dynamically typed language can have the overhead of one word per
object, for most objects. Only the size of arrays and strings is
stored after the header, but it would be a good idea anyway compared
to the current design - it would remove the artificial limit of object
sizes.

> Plus- does RTTI apply to non-objects? Ocaml has a lot of types that
> are not classes.

A possible answer: conceptually yes, physically it can be avoided for
unboxed ints or other unboxed variables whose type is known statically;
constants like the empty list can be boxed and allocated statically,
so they have almost the same overhead as currently (only the bit
pattern is not known until link time).

I don't claim that it would be easy to adapt to OCaml as it is.
I claim that it's not a bad idea in general.

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

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21 22:06         ` Michael Vanier
@ 2004-09-21 22:32           ` Brian Hurt
  2004-09-22  1:04           ` skaller
  1 sibling, 0 replies; 29+ messages in thread
From: Brian Hurt @ 2004-09-21 22:32 UTC (permalink / raw)
  To: Michael Vanier; +Cc: caml-list

On Tue, 21 Sep 2004, Michael Vanier wrote:

> Um, no, they didn't.  In fact, it's a completely different mechanism.  The
> compiler erases the generic information so that the JVM sees only old-style
> java classes without parameterization and adds casts where needed.  OK,
> this wasn't the greatest example in the world, because it relies massively
> on RTTI.

OK.  I'm not up on what precisely Java is doing here.  I note that they're 
also adding autoboxing/unboxing.

> I don't agree.  For instance, try implementing the equivalent of
> multimethods without some kind of downcast.  Of course, if a language
> supported multimethods from the get-go it would be even nicer, but very few
> languages do.  Now, if you're going to argue that wanting multimethods at
> all is a sign that you haven't thought through a problem carefully enough,
> we'll just have to agree to disagree.  I'm always suspicious of arguments
> that start off with "you really don't want to do that", because I can't say
> with any certainty what I will want to do or need to do 100% of the time.

Multimethods should use variant (tagged) types, not objects and 
downcasting.

For example, consider the case where I want to deal with a number, that 
could be an integer, a floating point number, or a complex (x + yi format) 
number.  I'd implement it like:

type number_t = 
    | Int of int
    | Float of float
    | Complex of float * float
;;

let add a b =
    match a, b with
        | Int(x), Int(y) 
        -> Int(x + y)
        
        | Int(x), Float(y) 
        | Float(y), Int(x)
        -> Float((float_of_int x) +. y)

        | Float(x), Float(y) -> Float(x +. y)

        | Int(x), Complex(yr, yi)
        | Complex(yr, yi), Float(x)
        -> Complex(((float_of_int x) +. yr), yi)

        | Float(x), Complex(yr, yi)
        | Complex(yr, yi), Float(x)
        -> Complex(x +. yr, yi)

        | Complex(xr, xi), Complex(yr, yi) ->
            Complex(xr +. yr, xi +. yi)
;;

This is what I meant by not everything in Ocaml needs to be objects.

Note that there is an advantage to how Ocaml does it- if you add a new tag 
to number_t, Ocaml will warn you in all the places you need to update to 
handle the new tag.


-- 
"Usenet is like a herd of performing elephants with diarrhea -- massive,
difficult to redirect, awe-inspiring, entertaining, and a source of
mind-boggling amounts of excrement when you least expect it."
                                - Gene Spafford 
Brian

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21 21:38       ` Brian Hurt
  2004-09-21 22:06         ` Michael Vanier
  2004-09-21 22:20         ` Marcin 'Qrczak' Kowalczyk
@ 2004-09-22  0:50         ` skaller
  2 siblings, 0 replies; 29+ messages in thread
From: skaller @ 2004-09-22  0:50 UTC (permalink / raw)
  To: caml-list

On Wed, 2004-09-22 at 07:38, Brian Hurt wrote:

> Downcasting is a sign you're doing something wrong.  If you knew the 
> object was a bar_t, why didn't it have the type bar_t from the get-go?  

I agree. However I'll add two explanations here.

(1) C++ and Java classes use nominal typing which
means they have a particular name. Two similar classes
with a different name are different. This is important
because the associated type is determined exclusively
by the name.

In Ocaml, the class name is irrelevant because they use
structural typing. This means that what counts is the
set of names of the methods and their types. So in Ocaml
two similar classes with the different names have the
*same* associated type. Of course you can name such
types, but the names are just aliases.

Structural typing is prone to errors where two
types intended to be distinct become interchangeable
"by accident" because they have the same method names and types
"by accident" but in practice this hardly ever happens.

OTOH structural typing is vastly superior to nominal
typing when it comes to subtyping. Algorithms can
be written requiring a particular type, and can be
applied to any class that has that type as a supertype,
just as in Java or C++. The difference is you don't
have to invade the class definition and add the name
of the supertype to the list of abstract bases/interfaces.

Therefore, the most fundamental principle of Object
Orientation -- Meyers Open/Closed principle -- 
is obeyed by Ocaml classes and NOT by C++ or Java.
It is this principle which helps provide encapsulation.

You could say Ocaml is more Object Oriented
than either C++ or Java because it obeys the
major principles better.

(2) In Ocaml we have two kinds of unions: ordinary
variants and polymorphic variants, aka sum types.

In C++ and Java, we don't have these types natively.
[C++ has a severely broken union]

So what programmers do to emulate them is use
inheritence. This is the primary reason both
C++ and java require downcasts.

So in summary: OO programmers are generally ignorant
of the very fundamentals of programming theory.
They're used to  dealing with all sorts of weird
problems representing simple data which arises
directly out from broken type systems C++ and Java
provide: a naturally algebraic representation
can't be found, because they only provide
products and not sums. So the programmer
turns to abstraction, but then has to
'unabstract' the abstraction using downcasts.

The worst thing about this is that inheritance
is used to provide two fundamentally distinct type
relations: abstraction/subtyping and unification.
In Ocaml, there are two distinct mechanisms.

No one would claim Ocaml is perfect, but it does
get the basics right. Note I didn't mention
the fact you also have first class function
types: this has nothing to do with functional
programming per se.

Its just that languages like Ocaml were designed
after doing basic mathematics, Java and C++
were not.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21 22:06         ` Michael Vanier
  2004-09-21 22:32           ` Brian Hurt
@ 2004-09-22  1:04           ` skaller
  1 sibling, 0 replies; 29+ messages in thread
From: skaller @ 2004-09-22  1:04 UTC (permalink / raw)
  To: caml-list

On Wed, 2004-09-22 at 08:06, Michael Vanier wrote:

> Um, no, they didn't.  In fact, it's a completely different mechanism.  The
> compiler erases the generic information so that the JVM sees only old-style
> java classes without parameterization and adds casts where needed.  OK,
> this wasn't the greatest example in the world, because it relies massively
> on RTTI.

Ocaml does this too. However, the polymorphism uses *static*
type checking to erase the type information, and doesn't
need to use RTTI.

BTW: Ocaml *does* provide limited RTTI and 
dynamic dispatch on that RTTI. If you examine:

type num = Int of int | Float of float

match x with
| Int x -> print_int x
| Float x -> print_float x

you can see that the match must use RTTI and it does.
However it isn't a full description of the type,
just an integral 'tag' allowing a switch to the 
correct case. Not enough information to check
the type -- the static type system has
checked already 'up to which variant' and the
rest is done at runtime.

Similarly, RTTI is used to do array bounds
checks in Ocaml: arrays typing is weaker
than in Pascal, which never needs array
bound checks, or Modula, where advanced
analysis can elide about 60% of such checks.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21 19:27     ` Michael Vanier
  2004-09-21 21:38       ` Brian Hurt
@ 2004-09-22  1:30       ` Jacques GARRIGUE
  2004-09-22  2:59         ` skaller
  1 sibling, 1 reply; 29+ messages in thread
From: Jacques GARRIGUE @ 2004-09-22  1:30 UTC (permalink / raw)
  To: mvanier; +Cc: caml-list

From: Michael Vanier <mvanier@cs.caltech.edu>
> > From: Jacques GARRIGUE <garrigue@kurims.kyoto-u.ac.jp>
> > 
> > There are two important differences between ocaml and other
> > OO-languages that have downcasting.
> > 
> > - inheritance is not subtyping. The subtyping relation being
> >   structural, a full fledge typecast would not only require to keep
> >   type information at runtime, but to embark a large part of the
> >   compiler to check subtyping. This might also be incredibly slow.
> > 
> >   As a result, downcast is only reasonable when we have both
> >   inheritance and subtyping. You're suddenly losing a large part of
> >   the language.
> 
> But java has interfaces (subtypes), and classes can implement interfaces
> (making them subtypes of the interface) without inheritance.  Furthermore,
> the class identity can be retrieved from an instance of an interface by
> using the instanceof operator.

Java interfaces are actually closer to inheritance than to subtyping.
For a class to support an interface, you must declare it when you
define the class, and you have no way to add a new interface
afterwards.
With ocaml class types, you can coerce an object to any type whose
methods it implements, even if the object comes from a class actually
defined before this class type.

For this reason, I would rather compare java interfaces to purely
virtual ocaml classes. Implementing a java inteface then amounts to
inheriting from a class whose methods are all virtual.
This is closer, because a java class includes extra code for all the
interfaces it is supposed to implement.

>From an implementation point of view, java interfaces are just a hack
to work around the absence of multiple inheritance.
And not very efficient at that: method calls through interfaces can be
slower than ocaml method calls, which have to be completely dynamic.

> >   Worse, even if you have a module interface
> >      class b :
> >        object
> >          inherit a
> >          ....
> >        end
> >   in ocaml this does _not_ mean that b inherits from a, just that it
> >   has at least a's methods and fields.
> >   So the semantics of downcast would not allow abstraction.
> 
> I don't understand the point you're trying to make here, but it seems like
> a is effectively equivalent to an interface in java (at least from your
> description).

The point is that b may actually have no relation whatsoever to a. It
just happens to implements all a's methods, and as result the above
syntax can be used to make the declaration shorter. If downcasting
were to depend on the inheritance relation (and in java it does, if
you rightly consider all the "implements" as weaker versions of
"inherits"), then there would be no way at runtime to see b as a
subclass of a, eventhough the above declaration lets you think this is
the case.

> > - classes may have type parameters. Assume a situation like
> >     class ['a] a = object ... end
> >   Then we cannot downcast any runtime object to "a", because we don't
> >   know what is its type parameter. Again, downcast would not mix well
> >   with other features of the language.
> 
> Java now has generics (type parameters), and I assume that it has to get
> around this situation somehow.

Well, I tried today with 1.5beta2, and it simply doesn't.

Actually, generics only provide very limited type safety if you start
using casts.
Look at the following program:

import java.util.*;

class Testgen {
  public static void main(String[] argv) {
      ArrayList<Integer> l = new ArrayList<Integer>();
      Object l1 = l;
      ArrayList<String> l2 = (ArrayList<String>)l1;
      l2.add("Hello");
      Integer n = l.get(0);
  }
}

When you compile it, you get a warning about the cast
(ArrayList<String>) not being checked. When you run it, you get a
runtime type error on the last line: not even when you try to add a
string to a list of integers, but when you extract an integer from a
list of integers!

I believe C# intends to do something better, but this is going to be
rather heavy-weight, and their subtyping relation is much simpler than
ocaml's.

> > So, while this is somehow unfortunate, there is no downcast in ocaml.
> 
> I'm sure there are good reasons for this, but I don't find the arguments
> you've presented above persuasive.  Not that I'm trying to hold java up as
> a shining example of the Right Thing; I'd much rather program in ocaml than
> java any day of the week.  But the lack of downcasting has frustrated me in
> the past (it's my #1 gripe about ocaml, with the lack of support for
> native-code shared libraries at #2).

There are various type-safe idioms to support downcasting.
Maybe it would be a good idea to collect them somewhere.

Yet I think that other people's comments are right: there are often
better ways than downcasting. They may mean that you lose in
modularity, but in my opinion you gain more in safety.

Jacques Garrigue

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-21 22:20         ` Marcin 'Qrczak' Kowalczyk
@ 2004-09-22  2:26           ` skaller
  2004-09-22  6:31             ` Marcin 'Qrczak' Kowalczyk
  0 siblings, 1 reply; 29+ messages in thread
From: skaller @ 2004-09-22  2:26 UTC (permalink / raw)
  To: caml-list

On Wed, 2004-09-22 at 08:20, Marcin 'Qrczak' Kowalczyk wrote:

> Attempts to avoid downcasts are often unmodular, they require to
> specify all possible variants in one place.

It makes no difference. You have do specify them all anyhow,
downcast or not.

> > Downcasting is a sign you're doing something wrong.
> 
> I disagree. It may be, or not. Just that OCaml doesn't support
> something doesn't imply that it must be evil.

The unstated assumption is that you want early error detection
and efficiency which static typing promises.

If you are willing to forgo these benefits -- and have
slow unreliable programs -- then you can use downcasts,
RTTI, or even code in Assmebler.

My typesetting tool Interscript uses Python for
dynamic message dispatch -- a certain class of
errors lead to exceptions being thrown which are
just ignored. This is intentional. The result
is sometimes bad output, so you have to actually
proofread the generated document to be sure
you got what you expected.

The reason is that (a) usually ignoring a
request to use a LaTeX feature in HTML is reasonable,
or vice versa. (b) termination of processing with
a weird error makes finding the problem harder
than generating bad output where you can actually
examine the consequences visually.

I.e. what I'm doing is even 'worse' than run
time error diagnosis -- I'm checking,
and then ignoring the fault :)

> Of course something is necessary to determine at runtime whether it's
> safe. I don't advocate unsafe constructs.

In the static typing world, 'safe' means errors are always
detected at compile time.

Clearly this is impossible in general, so safe is a
relative term. I consider Ocaml *unsafe* because
array bounds aren't checked at compile time.

Catching the error at run time is better than
not catching it -- but it still means the program
is unsafe.

Generally, we'd like to make programs safer where
possible. The problem with downcasting as a general
technique is that it bypasses static safety where
it is in fact desired and is available.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22  1:30       ` Jacques GARRIGUE
@ 2004-09-22  2:59         ` skaller
  0 siblings, 0 replies; 29+ messages in thread
From: skaller @ 2004-09-22  2:59 UTC (permalink / raw)
  To: caml-list

On Wed, 2004-09-22 at 11:30, Jacques GARRIGUE wrote:

> From an implementation point of view, java interfaces are just a hack
> to work around the absence of multiple inheritance.

I don't think this is quite right.

In C++ you can use 'mixin' abstract classes, however
the basic rule is that you do all the mixing with
the abstractions, providing subtyping, 
and then any mixing you do in providing an 
implementation is regarded as 'implementation inheritance'
which you should represent using private bases.

However this last rule isn't enforced. Java provides
two ways to enhance enforcement: it separates
the notion of the abstract class from the concrete
implementation, and it provides 'final' classes.

Thus, the idea isn't entirely a workaround for
lack of multiple inheritance, but instead a
refinement of more general and less secure C++
technology, which provides a bit more enforcement.

I.e: the separation is deliberate and based
on some concept of enforcement of constraints,
rather a workaround for a deficiency.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22  2:26           ` skaller
@ 2004-09-22  6:31             ` Marcin 'Qrczak' Kowalczyk
  2004-09-22  9:03               ` sejourne_kevin
                                 ` (5 more replies)
  0 siblings, 6 replies; 29+ messages in thread
From: Marcin 'Qrczak' Kowalczyk @ 2004-09-22  6:31 UTC (permalink / raw)
  To: skaller; +Cc: caml-list

skaller <skaller@users.sourceforge.net> writes:

>> Attempts to avoid downcasts are often unmodular, they require to
>> specify all possible variants in one place.
>
> It makes no difference. You have do specify them all anyhow,
> downcast or not.

It makes a difference because specifying them at the type definition
would introduce a dependency loop between modules. And it would be
unmodular: it would require changing some base module whenever a far
client module is added.

Apply this reasoning to the exn type. Why don't you define all exn
constructors in one place?

> The unstated assumption is that you want early error detection
> and efficiency which static typing promises.

It's impossible in general. Only some errors are detectable statically
in practice.

> In the static typing world, 'safe' means errors are always
> detected at compile time.

No practical language is safe according to this definition, so this
definition is useless.

> Generally, we'd like to make programs safer where possible.

This is the catch: "where possible". I would add: "where practical";
sometimes the cost outweights the benefits. For example static
detection of possible division by 0 would be impractical. You would
have to either embed a proof checker in the language in order to be
able to convince the compiler that the number can't be 0, or not use
exceptions at all and have all partial functions return a result in
"option" type or similar, with manual propagation of errors.

And guess what? No language I know checks division by 0 statically
(except proof checkers, but they are not suitable for writing big
programs - too much work). Because it would make programs less robust,
not more. Because you would not use exceptions, and manual propagation
of errors is more error-prone than using exceptions, and it causes
more problems when the set of possible exceptions raised in a given
part of code is changed.

> The problem with downcasting as a general technique is that it
> bypasses static safety where it is in fact desired and is available.

It's not available because it can't express what downcasts provide:
the ability to add "constructors" to a type in a modular way.

According to your beliefs, you should advocate removing exceptions
from OCaml. Because they make the type independent from the set of
ways in which a program can fail, and thus remove the ability to
statically check whether all possible errors are caught. You should
always use explicit algebraic types to encode the outcome, no?

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

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22  6:31             ` Marcin 'Qrczak' Kowalczyk
@ 2004-09-22  9:03               ` sejourne_kevin
  2004-09-22 10:29               ` Richard Jones
                                 ` (4 subsequent siblings)
  5 siblings, 0 replies; 29+ messages in thread
From: sejourne_kevin @ 2004-09-22  9:03 UTC (permalink / raw)
  To: caml-list

Marcin 'Qrczak' Kowalczyk wrote:
> skaller <skaller@users.sourceforge.net> writes:
> 
> 
>>>Attempts to avoid downcasts are often unmodular, they require to
>>>specify all possible variants in one place.
>>
>>It makes no difference. You have do specify them all anyhow,
>>downcast or not.
> 
> 
> It makes a difference because specifying them at the type definition
> would introduce a dependency loop between modules. And it would be
> unmodular: it would require changing some base module whenever a far
> client module is added.
> 
> Apply this reasoning to the exn type. Why don't you define all exn
> constructors in one place?

I think there is no problems with exceptions. But if you have problems 
managing exceptions in large modules have you try something like this ?

here an example:
I define all my exceptions like this :

let errors = ref [];;

(*to define an error*)
(*errors     "the exception" , the new value*)
errors :=   ("div by zero"   ,0)              :: (!errors);;

And the functions catch errors in this way:
let truc () =
   try
     ...
   with
      ... all Ocaml pre-defined exceptions
     | exn -> (* my exceptions in  errors list ref *)
	let s = Printexc.to_string exn in
	  ... Lex & Parse 's' in (fst errors) ref list , then handle error ...
;;

If exceptions are complex I can use polymorphic variants
for the "new value".

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22  6:31             ` Marcin 'Qrczak' Kowalczyk
  2004-09-22  9:03               ` sejourne_kevin
@ 2004-09-22 10:29               ` Richard Jones
  2004-09-22 18:39                 ` Brian Hurt
  2004-09-22 10:50               ` skaller
                                 ` (3 subsequent siblings)
  5 siblings, 1 reply; 29+ messages in thread
From: Richard Jones @ 2004-09-22 10:29 UTC (permalink / raw)
  To: caml-list

[-- Attachment #1: Type: text/plain, Size: 1654 bytes --]

On Wed, Sep 22, 2004 at 08:31:38AM +0200, Marcin 'Qrczak' Kowalczyk wrote:
> skaller <skaller@users.sourceforge.net> writes:
> 
> >> Attempts to avoid downcasts are often unmodular, they require to
> >> specify all possible variants in one place.
> >
> > It makes no difference. You have do specify them all anyhow,
> > downcast or not.
> 
> It makes a difference because specifying them at the type definition
> would introduce a dependency loop between modules. And it would be
> unmodular: it would require changing some base module whenever a far
> client module is added.

I've tended to stop using and thinking in OO terms since starting to
use OCaml.  In particular, when I need a data structure of some sort,
I just use a data structure (tuple, struct, variant whatever).  Before
coming to OCaml, data structure implied "class" for me.

The advantage to me is that now when I change the data structure the
compiler catches all the places in the code which I need to change, so
I go through and methodically change them.

But the OCaml assumption here is that you program is one big
monolithic entity, for which you have source (and are recompiling) all
parts.  This goes against the OO theory of "reuse" - particularly of
reuse of binary classes, which I don't think I've ever actually used
in practice anyway.

Rich.

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
NET::FTPSERVER is a full-featured, secure, configurable, database-backed
FTP server written in Perl: http://www.annexia.org/freeware/netftpserver/

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22  6:31             ` Marcin 'Qrczak' Kowalczyk
  2004-09-22  9:03               ` sejourne_kevin
  2004-09-22 10:29               ` Richard Jones
@ 2004-09-22 10:50               ` skaller
  2004-09-22 12:03               ` Alain Frisch
                                 ` (2 subsequent siblings)
  5 siblings, 0 replies; 29+ messages in thread
From: skaller @ 2004-09-22 10:50 UTC (permalink / raw)
  To: Marcin 'Qrczak' Kowalczyk; +Cc: caml-list

On Wed, 2004-09-22 at 16:31, Marcin 'Qrczak' Kowalczyk wrote:

> sometimes the cost outweights the benefits. For example static
> detection of possible division by 0 would be impractical.

You could use a monad .. :)

> And guess what? No language I know checks division by 0 statically

Hehe --:>

include "std";
print (1/0); endl;

[skaller@pelican] ~>flxg aa
EXCEPTION
Division_by_zero

That's a compile time error (Dang -- and its a bug too,
the error should report the location .. :)

But I assume you mean 'exhaustively'.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22  6:31             ` Marcin 'Qrczak' Kowalczyk
                                 ` (2 preceding siblings ...)
  2004-09-22 10:50               ` skaller
@ 2004-09-22 12:03               ` Alain Frisch
  2004-09-22 12:50               ` Cláudio Valente
  2004-09-22 18:42               ` Brian Hurt
  5 siblings, 0 replies; 29+ messages in thread
From: Alain Frisch @ 2004-09-22 12:03 UTC (permalink / raw)
  To: Marcin 'Qrczak' Kowalczyk; +Cc: skaller, caml-list

On Wed, 22 Sep 2004, Marcin 'Qrczak' Kowalczyk wrote:

> This is the catch: "where possible". I would add: "where practical";
> sometimes the cost outweights the benefits. For example static
> detection of possible division by 0 would be impractical. You would
> have to either embed a proof checker in the language in order to be
> able to convince the compiler that the number can't be 0, or not use
> exceptions at all and have all partial functions return a result in
> "option" type or similar, with manual propagation of errors.

You don't necessarily have to use a proof checker. What about using a type
system, or a(nother kind of) static analysis ?  E.g. detection of division
by 0 can be done with interval arithmetic, and it might work well in
practice.

> And guess what? No language I know checks division by 0 statically
> (except proof checkers, but they are not suitable for writing big
> programs - too much work).

        CDuce version 0.2.1+1

# fun (x : Int) : Int = 1 div x;;
Warning at chars 22-29:
This operator may fail
- : Int -> Int = <fun>

# fun (x : 0--*) : Int = 1 div x;;
Warning at chars 23-30:
This operator may fail
- : 0--* -> Int = <fun>

# fun (x : 1--*) : Int = 1 div x;;
- : 1--* -> Int = <fun>

# fun (x : 1--*) : Int = 1 div (x + x);;
- : 1--* -> Int = <fun>

# fun (x : 1--*) : Int = 1 div (x - x + x);;
Warning at chars 23-40:
This operator may fail
- : 1--* -> Int = <fun>

(type 1--* means: "positive integers")

To get rid of warning (or compile-time error) when the type system is not
precise enough (the last example above), you can always do an
explicit check:

# fun (x : 1--*) : Int =
   match x - x + x with
   | y & (1--*) -> 1 div y
   | _ -> raise "Bla";;
- : 1--* -> Int = <fun>


-- Alain

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22  6:31             ` Marcin 'Qrczak' Kowalczyk
                                 ` (3 preceding siblings ...)
  2004-09-22 12:03               ` Alain Frisch
@ 2004-09-22 12:50               ` Cláudio Valente
  2004-09-22 13:15                 ` Marcin 'Qrczak' Kowalczyk
  2004-09-22 18:42               ` Brian Hurt
  5 siblings, 1 reply; 29+ messages in thread
From: Cláudio Valente @ 2004-09-22 12:50 UTC (permalink / raw)
  To: Marcin 'Qrczak' Kowalczyk; +Cc: skaller, caml-list

Em Quarta, 22 de Setembro de 2004 07:31, o Marcin 'Qrczak' Kowalczyk escreveu:
> And guess what? No language I know checks division by 0 statically
> (except proof checkers, but they are not suitable for writing big
> programs - too much work)

12>0 cvalente@link Stats 54$ cat t.pl
sub t{
print 1/0;
}
13>0 cvalente@link Stats 54$ perl -c t.pl
Illegal division by zero at t.pl line 2.

perl -c stands for check syntax

gcc also has this. It gives a warning

gcc -c t.c
t.c: In function `t':
t.c:2: warning: division by zero

and it does even more:

24>0 cvalente@link Stats 54$ cat t.cpp
const int X = 1-1;
int t(int i){
        return i/X;
}
25>0 cvalente@link Stats 54$ g++ -c t.cpp
t.cpp: In function `int t(int)':
t.cpp:3: warning: division by zero in `i / 0'

These are not exhaustive tests, but they are good enough to catch many common 
errors.

-- 
Cláudio Valente

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22 12:50               ` Cláudio Valente
@ 2004-09-22 13:15                 ` Marcin 'Qrczak' Kowalczyk
  2004-09-22 15:50                   ` skaller
  0 siblings, 1 reply; 29+ messages in thread
From: Marcin 'Qrczak' Kowalczyk @ 2004-09-22 13:15 UTC (permalink / raw)
  To: cvalente; +Cc: skaller, caml-list

Cláudio Valente <cvalente@co.sapo.pt> writes:

>> And guess what? No language I know checks division by 0 statically
>> (except proof checkers, but they are not suitable for writing big
>> programs - too much work)

> These are not exhaustive tests, but they are good enough to catch
> many common errors.

I meant exhaustive tests, not heuristics for easy cases where the
divisor is constant.

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

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22 13:15                 ` Marcin 'Qrczak' Kowalczyk
@ 2004-09-22 15:50                   ` skaller
  0 siblings, 0 replies; 29+ messages in thread
From: skaller @ 2004-09-22 15:50 UTC (permalink / raw)
  To: Marcin 'Qrczak' Kowalczyk; +Cc: cvalente, caml-list

On Wed, 2004-09-22 at 23:15, Marcin 'Qrczak' Kowalczyk wrote:
> Cláudio Valente <cvalente@co.sapo.pt> writes:

> I meant exhaustive tests, not heuristics for easy cases where the
> divisor is constant.

It is of course possible to it entirely statically right
now in Ocaml by using an abstract type for a non-zero int.
Not as good as CDuce's interval arithmetic because you have
to handle the 0 in the int-> nonzero_int conversion, but still
afterwards you can divide without an exception.

Some functions, eg multiplication, preserve non-zeroness,
so in many cases you can use static typing to avoid
gratuitous checks for zero. 

As you may have noted in my Felix example -- exceptions
are just too powerful: I forgot to catch the exception. 
I fixed my modulus function too .. but no doubt I have
missed others. Perhaps static checking would make
programming harder -- but nothing is harder than
exhaustively testing a complex program.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22 10:29               ` Richard Jones
@ 2004-09-22 18:39                 ` Brian Hurt
  0 siblings, 0 replies; 29+ messages in thread
From: Brian Hurt @ 2004-09-22 18:39 UTC (permalink / raw)
  To: Richard Jones; +Cc: caml-list

On Wed, 22 Sep 2004, Richard Jones wrote:

> But the OCaml assumption here is that you program is one big
> monolithic entity, for which you have source (and are recompiling) all
> parts.  This goes against the OO theory of "reuse" - particularly of
> reuse of binary classes, which I don't think I've ever actually used
> in practice anyway.

Note that OO resuse is not the only theory of reuse possible.  Partial 
function application, higher order functions, modules and functors, 
universal types ('a), etc. also allow incredible code reuse, without 
touching objects.  In OO program, the object or class is the building 
block of reuse- in functional programming, it's the function.

If all you know is hammers, a cresent wrench is seen as a badly designed 
hammer.

-- 
"Usenet is like a herd of performing elephants with diarrhea -- massive,
difficult to redirect, awe-inspiring, entertaining, and a source of
mind-boggling amounts of excrement when you least expect it."
                                - Gene Spafford 
Brian

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22  6:31             ` Marcin 'Qrczak' Kowalczyk
                                 ` (4 preceding siblings ...)
  2004-09-22 12:50               ` Cláudio Valente
@ 2004-09-22 18:42               ` Brian Hurt
  2004-09-22 18:44                 ` Marcin 'Qrczak' Kowalczyk
  5 siblings, 1 reply; 29+ messages in thread
From: Brian Hurt @ 2004-09-22 18:42 UTC (permalink / raw)
  To: Marcin 'Qrczak' Kowalczyk; +Cc: caml-list

On Wed, 22 Sep 2004, Marcin 'Qrczak' Kowalczyk wrote:

> It makes a difference because specifying them at the type definition
> would introduce a dependency loop between modules. And it would be
> unmodular: it would require changing some base module whenever a far
> client module is added.
> 
> Apply this reasoning to the exn type. Why don't you define all exn
> constructors in one place?

Ignoring the fact that exceptions are built into the language, I'd read
section 4.2 "Polymorphic Variants" of the Ocaml language manual for how to
get around this.

-- 
"Usenet is like a herd of performing elephants with diarrhea -- massive,
difficult to redirect, awe-inspiring, entertaining, and a source of
mind-boggling amounts of excrement when you least expect it."
                                - Gene Spafford 
Brian

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22 18:42               ` Brian Hurt
@ 2004-09-22 18:44                 ` Marcin 'Qrczak' Kowalczyk
  2004-09-22 19:18                   ` Brian Hurt
  0 siblings, 1 reply; 29+ messages in thread
From: Marcin 'Qrczak' Kowalczyk @ 2004-09-22 18:44 UTC (permalink / raw)
  To: Brian Hurt; +Cc: caml-list

Brian Hurt <bhurt@spnz.org> writes:

>> Apply this reasoning to the exn type. Why don't you define all exn
>> constructors in one place?
>
> Ignoring the fact that exceptions are built into the language, I'd read
> section 4.2 "Polymorphic Variants" of the Ocaml language manual for how to
> get around this.

It helps only in some cases. In particular it's not expressive enough
to replace exn.

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

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Caml-list] Re: OCAML Downcasting?
  2004-09-22 18:44                 ` Marcin 'Qrczak' Kowalczyk
@ 2004-09-22 19:18                   ` Brian Hurt
  0 siblings, 0 replies; 29+ messages in thread
From: Brian Hurt @ 2004-09-22 19:18 UTC (permalink / raw)
  To: Marcin 'Qrczak' Kowalczyk; +Cc: caml-list

On Wed, 22 Sep 2004, Marcin 'Qrczak' Kowalczyk wrote:

> Brian Hurt <bhurt@spnz.org> writes:
> 
> >> Apply this reasoning to the exn type. Why don't you define all exn
> >> constructors in one place?
> >
> > Ignoring the fact that exceptions are built into the language, I'd read
> > section 4.2 "Polymorphic Variants" of the Ocaml language manual for how to
> > get around this.
> 
> It helps only in some cases. In particular it's not expressive enough
> to replace exn.

No.  That's why exceptions were built into the language.

It does, however, allow you to 'retrofit' RTTI onto any type:

let do_stuff = function
    | `Foo of foo ->
        (* our argument is only of type foo, only do stuff we can
           do with a foo.
         *)
        foo#do_foo_stuff()
    | `Bar of bar ->
        (* In addition to being a foo, our argument is also a bar.
           Do foo stuff and bar stuff.
         *)
        bar#do_foo_stuff ();
        bar#do_bar_stuff ()
;;

As for interpreting a RTTI language, I do a full on interpreter.  I don't
try to use Ocaml as an intermediate language.  Every object gets a
StringMap ( = Map.Make(String)) to allow me to look up the member function
definition from the function name.  I collect the arguments up into
another StringMap (mapping from the name of the argument to the value),
and pass that it to any function I call.  Yes, you have to add the type 
information to every object, instead of having the compiler do it for you.

There is a whole long list of features Ocaml has that Java lacks, or 
requires you to use broken kludges to work around.  It sounds like- the 
better part of a decade later- they finally figured out that univeral 
types and being able to express types like 'int array list list' is a good 
thing.  Partial function application still has to be kludged with "doit" 
objects- objects and interfaces with single member functions- the "doit" 
function.  And so on, and so forth.  

The trick is, when programming in Java, to "think in Java", not in Ocaml
(or C).  Likewise, the trick is, when programming in Ocaml, to think in
Ocaml.  The question is not "how do I make this particular Java solution
to the problem work?"  The question is "how do I solve this problem in
Ocaml?"

-- 
"Usenet is like a herd of performing elephants with diarrhea -- massive,
difficult to redirect, awe-inspiring, entertaining, and a source of
mind-boggling amounts of excrement when you least expect it."
                                - Gene Spafford 
Brian

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2004-09-22 19:08 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <ci7tcf$qqf$1@wolfberry.srv.cs.cmu.edu>
     [not found] ` <ci9ggm$i6p$1@wolfberry.srv.cs.cmu.edu>
2004-09-21  8:03   ` [Caml-list] Re: OCAML Downcasting? Jacques GARRIGUE
2004-09-21  8:43     ` Damien Pous
2004-09-21  9:15       ` Jacques GARRIGUE
2004-09-21  9:29         ` skaller
2004-09-21  9:49           ` Jacques GARRIGUE
2004-09-21  9:34         ` Stefano Zacchiroli
2004-09-21  9:56           ` Jacques GARRIGUE
2004-09-21 19:27     ` Michael Vanier
2004-09-21 21:38       ` Brian Hurt
2004-09-21 22:06         ` Michael Vanier
2004-09-21 22:32           ` Brian Hurt
2004-09-22  1:04           ` skaller
2004-09-21 22:20         ` Marcin 'Qrczak' Kowalczyk
2004-09-22  2:26           ` skaller
2004-09-22  6:31             ` Marcin 'Qrczak' Kowalczyk
2004-09-22  9:03               ` sejourne_kevin
2004-09-22 10:29               ` Richard Jones
2004-09-22 18:39                 ` Brian Hurt
2004-09-22 10:50               ` skaller
2004-09-22 12:03               ` Alain Frisch
2004-09-22 12:50               ` Cláudio Valente
2004-09-22 13:15                 ` Marcin 'Qrczak' Kowalczyk
2004-09-22 15:50                   ` skaller
2004-09-22 18:42               ` Brian Hurt
2004-09-22 18:44                 ` Marcin 'Qrczak' Kowalczyk
2004-09-22 19:18                   ` Brian Hurt
2004-09-22  0:50         ` skaller
2004-09-22  1:30       ` Jacques GARRIGUE
2004-09-22  2:59         ` skaller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).