* 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
* OO design
@ 2006-05-05 9:35 David Baelde
2006-05-05 10:47 ` [Caml-list] " Gerd Stolpmann
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: David Baelde @ 2006-05-05 9:35 UTC (permalink / raw)
To: Ocaml
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.
--
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 ` 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
* 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 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-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-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-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
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