caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Re: [Caml-list] OO design
@ 2006-05-08 22:59 yoann padioleau
  0 siblings, 0 replies; 7+ messages in thread
From: yoann padioleau @ 2006-05-08 22:59 UTC (permalink / raw)
  To: David Teller, caml-list


 
> Which brings us to a question : how do you enforce protocols in OCaml ?
> 
> Say, is there a "good" way of rewriting file-related operations so that, say, 
> ProtocolUnix.read and ProtocolUnix.write *statically* only accept opened 
> files, and in addition, ProtocolUnix.write only accepts files which have been 
> opened with write priviledges ?

Have different types,  in_channel  and out_channel. But ocaml already have this.
The problem is that when you close a channel, ocaml does not warn you
if you try to read from a close channel.

> 
> I mean, there are manners of checking this with, say, model checking tools. In 
> the specific case of file management, I guess we can do it with a little bit 
> of simple subclassing, but I assume there's a large run-time penalty for this 
> extra bit of checking, due to the management of objects by OCaml. Has anyone 
> attempted to determine how well this scales up ? Or explored other options ?

Using higher order functions.
Instead of having a  open/read/close sequence protocol that you must follow, 
enforce such a protocol by defining a higher order function let's say
with_open_out_file that do all that for you under the hood.


with_open_out_file "/tmp/test.txt" (fun write_func -> 
 (* you can call write_func that do the writing *)
  write_func "toto";
  write_func "titi";
 );
 


let with_open_out_file file f = 
 let chan = open_out file in
 let read_func = output_string chan in

  try (
   f read_func;
   close_out chan;
  ) 
 with 
  x -> close_out chan; raise x


Note how the channel is automatically closed for you. 


This technique is used in Lisp library I think.


 


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

* Re: [Caml-list] OO design
  2006-05-08 21:29   ` David Teller
@ 2006-05-08 21:36     ` Dan Grossman
  0 siblings, 0 replies; 7+ messages in thread
From: Dan Grossman @ 2006-05-08 21:36 UTC (permalink / raw)
  To: David Teller; +Cc: caml-list


Phantom types are a programming idiom that can often pull off this sort 
of thing.

--Dan

David Teller wrote:
> On Monday 08 May 2006 05:17, Jacques Garrigue wrote:
> 
>>I would be tempted to say: there is no answer.
>>Ocaml objects are not about enforcing protocols, but about allowing
>>inheritance and structural subtyping, and this does not fit well with
>>your problem.
> 
> 
> Which brings us to a question : how do you enforce protocols in OCaml ?
> 
> Say, is there a "good" way of rewriting file-related operations so that, say, 
> ProtocolUnix.read and ProtocolUnix.write *statically* only accept opened 
> files, and in addition, ProtocolUnix.write only accepts files which have been 
> opened with write priviledges ?
> 
> I mean, there are manners of checking this with, say, model checking tools. In 
> the specific case of file management, I guess we can do it with a little bit 
> of simple subclassing, but I assume there's a large run-time penalty for this 
> extra bit of checking, due to the management of objects by OCaml. Has anyone 
> attempted to determine how well this scales up ? Or explored other options ?
> 
> Cheers,
>  David
> 
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs


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

* Re: [Caml-list] OO design
  2006-05-08  3:17 ` Jacques Garrigue
@ 2006-05-08 21:29   ` David Teller
  2006-05-08 21:36     ` Dan Grossman
  0 siblings, 1 reply; 7+ messages in thread
From: David Teller @ 2006-05-08 21:29 UTC (permalink / raw)
  To: caml-list

On Monday 08 May 2006 05:17, Jacques Garrigue wrote:
> I would be tempted to say: there is no answer.
> Ocaml objects are not about enforcing protocols, but about allowing
> inheritance and structural subtyping, and this does not fit well with
> your problem.

Which brings us to a question : how do you enforce protocols in OCaml ?

Say, is there a "good" way of rewriting file-related operations so that, say, 
ProtocolUnix.read and ProtocolUnix.write *statically* only accept opened 
files, and in addition, ProtocolUnix.write only accepts files which have been 
opened with write priviledges ?

I mean, there are manners of checking this with, say, model checking tools. In 
the specific case of file management, I guess we can do it with a little bit 
of simple subclassing, but I assume there's a large run-time penalty for this 
extra bit of checking, due to the management of objects by OCaml. Has anyone 
attempted to determine how well this scales up ? Or explored other options ?

Cheers,
 David


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

* Re: [Caml-list] OO design
  2006-05-05  9:35 David Baelde
  2006-05-05 10:47 ` [Caml-list] " Gerd Stolpmann
  2006-05-05 13:00 ` Remi Vanicat
@ 2006-05-08  3:17 ` Jacques Garrigue
  2006-05-08 21:29   ` David Teller
  2 siblings, 1 reply; 7+ messages in thread
From: Jacques Garrigue @ 2006-05-08  3:17 UTC (permalink / raw)
  To: david.baelde; +Cc: caml-list

From: "David Baelde" <david.baelde@gmail.com>

> I'm no OO guru, so my question may be irrelevant, or there just might
> not be an answer, which wouldn't hurt..
> 
> Let's say that I have a base class, with some kind of activation
> procedure: anybody wanting to use the class must call #enter before,
> and then call #leave for releasing. Internally, the methods #do_enter
> and #do_leave are called respectively at the first #enter and last
> #leave.
> 
> Nobody should call the #do_* directly, and I'd also like to make sure
> the #enter and #leave are never overriden, since their behaviour is
> important and actually much more complex than what I said.
> 
> I could just rely on the user who derives my base class, but let's see
> what we can do. First the #do_* should be made private, so they can be
> defined in the derived classes, but never called from the outside. To
> avoid the overriding of #enter and #leave the only solution seems to
> make them normal functions instead of methods. But then how could
> #enter call #do_enter ? I tried to first define the class with public
> #enter and make that method private in the interface, but OCaml told
> me that was impossible.

I would be tempted to say: there is no answer.
Ocaml objects are not about enforcing protocols, but about allowing
inheritance and structural subtyping, and this does not fit well with
your problem.
There are many things you can try to make it harder to derive incorrect
classes, but basically if the user wants to do it, he can.

Yet, since it seems that you are already relying on the (library)
programmer to write correct code for the #do_* methods, another point
of view might be that you just want to make sure that only the final user
of objects cannot break things. Then the technique described in other
answers make sense, for instance prohibiting inheritance from an
already completed class.
An even stronger protection is to make object types private. This way you
are sure than nobody can forge an object of the same type, and you can
even hide public methods if you wish. But you loose inheritance.
See the object example in my paper on private rows about how to do this.

Combining structural subtyping and modular privacy would introduce a
lot extra complexity in the type system.

Jacques Garrigue


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

* Re: [Caml-list] OO design
  2006-05-05 13:00 ` Remi Vanicat
@ 2006-05-05 19:32   ` Andrej Bauer
  0 siblings, 0 replies; 7+ messages in thread
From: Andrej Bauer @ 2006-05-05 19:32 UTC (permalink / raw)
  To: Remi Vanicat; +Cc: caml-list

Remi Vanicat wrote:
> 2006/5/5, David Baelde <david.baelde@gmail.com>: 
> after this, the only way to produce an object of type enter is to call
> the original enter method (same for leave).

... or throw an exception, or loop forever, or print a poem on sreen
then call the original function, or call original enter twice, or call
original enter, then original leave, then original enter, etc.

Andrej


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

* Re: [Caml-list] OO design
  2006-05-05  9:35 David Baelde
  2006-05-05 10:47 ` [Caml-list] " Gerd Stolpmann
@ 2006-05-05 13:00 ` Remi Vanicat
  2006-05-05 19:32   ` Andrej Bauer
  2006-05-08  3:17 ` Jacques Garrigue
  2 siblings, 1 reply; 7+ messages in thread
From: Remi Vanicat @ 2006-05-05 13:00 UTC (permalink / raw)
  To: david.baelde; +Cc: Ocaml

2006/5/5, David Baelde <david.baelde@gmail.com>:
> Hi,
>
> I'm no OO guru, so my question may be irrelevant, or there just might
> not be an answer, which wouldn't hurt..
>
> Let's say that I have a base class, with some kind of activation
> procedure: anybody wanting to use the class must call #enter before,
> and then call #leave for releasing. Internally, the methods #do_enter
> and #do_leave are called respectively at the first #enter and last
> #leave.
>
> Nobody should call the #do_* directly, and I'd also like to make sure
> the #enter and #leave are never overriden, since their behaviour is
> important and actually much more complex than what I said.

If the solution given Gerd Stolpmann have the problem to disallow the
inheritence, I've another that make ineritence and overriding enter
and leave possible, but ensure that method that overide enter and
leave do call the old enter and leave :

struct
  type enter = unit
  type leave = unit
  class foo =
     method enter ... : enter = ....
     method leave ....: leave = ...
     ....
   end
end : sig
  type enter
  type leave
  class foo :
    method enter : ... -> enter
    method leave : ... -> leave
  end
end

after this, the only way to produce an object of type enter is to call
the original enter method (same for leave). And as method that overide
enter must have the same type, the have to call the enter method to
have it (well, there might be other way, but the user of the method
have to make thing complicated for this).

Another plus of this method of doing it is that if you haev e method of type
  method bar : enter -> unit
then one can only call it if he had call previously the enter method.


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

* Re: [Caml-list] OO design
  2006-05-05  9:35 David Baelde
@ 2006-05-05 10:47 ` Gerd Stolpmann
  2006-05-05 13:00 ` Remi Vanicat
  2006-05-08  3:17 ` Jacques Garrigue
  2 siblings, 0 replies; 7+ messages in thread
From: Gerd Stolpmann @ 2006-05-05 10:47 UTC (permalink / raw)
  To: david.baelde; +Cc: Ocaml

Am Freitag, den 05.05.2006, 11:35 +0200 schrieb David Baelde:
> Hi,
> 
> I'm no OO guru, so my question may be irrelevant, or there just might
> not be an answer, which wouldn't hurt..
> 
> Let's say that I have a base class, with some kind of activation
> procedure: anybody wanting to use the class must call #enter before,
> and then call #leave for releasing. Internally, the methods #do_enter
> and #do_leave are called respectively at the first #enter and last
> #leave.
> 
> Nobody should call the #do_* directly, and I'd also like to make sure
> the #enter and #leave are never overriden, since their behaviour is
> important and actually much more complex than what I said.
> 
> I could just rely on the user who derives my base class, but let's see
> what we can do. First the #do_* should be made private, so they can be
> defined in the derived classes, but never called from the outside. To
> avoid the overriding of #enter and #leave the only solution seems to
> make them normal functions instead of methods. But then how could
> #enter call #do_enter ? I tried to first define the class with public
> #enter and make that method private in the interface, but OCaml told
> me that was impossible.
> 
> I'm just curious if anybody has an opinion/idea about that.

There is an easy solution if you completely forbid subclassing (see
below). However, there is no water-proof solution, because class types
are structural in O'Caml, i.e. you cannot prevent that a user simulates
subclassing using this style:

class pirate_foo (foo : official_foo) =
  object
    method enter = ...
    method leave = ...
    method other_method = foo # other_method
  end

If you want to safely encapsulate a certain invariant into a structure
you must go with modules/functors in O'Caml.

To forbid explicit subclassing just do not to export the class as such:

module Foo : sig
 class type foo_type =
   object
     method enter : ...
     method leave : ...
     ...
   end

 val create_foo : ... -> foo_type
end = struct
 class type foo_type =
   object
     method enter : ...
     method leave : ...
     ...
   end

 class foo ... : foo_type =
    object  
     method enter ... = ...
     method leave ... = ...
     ...
   end

 let create_foo ... = new foo ...
end

Without class, the user can no longer inherit from it. The created
object, however, is fully usable.

I do not see a way how to completely hide enter and leave from the class
type. 

Gerd
-- 
------------------------------------------------------------
Gerd Stolpmann * Viktoriastr. 45 * 64293 Darmstadt * Germany 
gerd@gerd-stolpmann.de          http://www.gerd-stolpmann.de
Phone: +49-6151-153855                  Fax: +49-6151-997714
------------------------------------------------------------


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

end of thread, other threads:[~2006-05-08 22:59 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-05-08 22:59 [Caml-list] OO design yoann padioleau
  -- strict thread matches above, loose matches on Subject: below --
2006-05-05  9:35 David Baelde
2006-05-05 10:47 ` [Caml-list] " Gerd Stolpmann
2006-05-05 13:00 ` Remi Vanicat
2006-05-05 19:32   ` Andrej Bauer
2006-05-08  3:17 ` Jacques Garrigue
2006-05-08 21:29   ` David Teller
2006-05-08 21:36     ` Dan Grossman

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).