caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Smells like duck-typing
@ 2007-10-17 13:35 Dario Teixeira
  2007-10-17 14:13 ` [Caml-list] " Arnaud Spiwack
                   ` (7 more replies)
  0 siblings, 8 replies; 55+ messages in thread
From: Dario Teixeira @ 2007-10-17 13:35 UTC (permalink / raw)
  To: caml-list

Hi,

I have been trying to reach a sane modelling in OCaml for a "story"
data structure in a CMS.  The problem is that I find myself needing
a degree of expressiveness that I can't find in the language!  I do
have a working, tentative solution, but it has a few ugly aspects
that I would very much like to improve.  Details follow.  (Sorry
for the long post; at least I hope it's not too dense and hard to
follow).

A "full" story record is defined like this:

type full_t =
	{
	id: int;
	title: string;
	intro: string;
	body: string;
	}

(in reality there are other fields, but I'll ommit them for the sake
of clarity).  In addition, stories can also come in "blurb" and "fresh"
types, which are essentially (non-disjoint) subsets of the type above:

type blurb_t =				type fresh_t =
	{					{
	id: int;				title: string;
	title: string;				intro: string;
	intro: string;				body: string;
	}					}


At last, I have a function "print_metadata" that takes as parameter
either a "full" or a "blurb" story, printing its id and title:

let print_metadata s =
	Printf.printf "%d: %s\n" s.id s.title

Now, I have been looking for the best way to model this situation
in OCaml.  Here are some options:

a) Use record types, as shown above.  However, to avoid namespace clashes,
   this would entail putting each record in its own module (neat) or at
   least salting each field name (ugly).  Suppose that I opt for the former
   option and create the modules Full, Blurb, and Fresh, each with a type t:

   type story_t = [`Full of Full.t | `Blurb of Blurb.t | `Fresh of Fresh.t]

   Note that I have chosen a polymorphic variant because print_metadata only
   makes sense for Full.t and Blurb.t types.  However, this solution means
   there can't be any code sharing between the two branchings, which is just
   ridiculous considering they are essentially identical:  (and in the real
   world, print_metadata is a much bigger function).

   let print_metadata = function
	| `Full s  -> Printf.printf "%d: %s\n" s.Full.id s.Full.title
	| `Blurb s -> Printf.printf "%d: %s\n" s.Blurb.id s.Blurb.title

b) Use only full_t and make all fields option types.  However, not only is
   this cumbersome to use, but is also conceptually wrong, because it does
   not capture the fact that, for example, all "blurb" stories have three
   *mandatory* fields.

c) Actually put the "Objective" part of OCaml to use.  This is the solution
   I am using at the moment.  This is what it looks like:

   class story (id, title, intro, body) =
   object
   	val id: int option = id
   	val title: string option = title
   	val intro: string option = intro
   	val body: string option = body
   
   	method id =
   		match id with
   		| Some thing -> thing
   		| None -> failwith "oops"
   
   	method title =
   		match title with
   		| Some thing -> thing
   		| None -> failwith "oops"
   
   	method intro =
   		match intro with
   		| Some thing -> thing
   		| None -> failwith "oops"
   
   	method body =
   		match body with
   		| Some thing -> thing
   		| None -> failwith "oops"
   end

   
   class full (id, title, intro, body) =
   object
   	inherit story (Some id, Some title, Some intro, Some body)
   end
   
   class blurb (id, title, intro) =
   object
   	inherit story (Some id, Some title, Some intro, None)
   end
   
   class fresh (title, intro, body) =
   object
   	inherit story (None, Some title, Some intro, Some body)
   end

   
   let print_metadata s =
   	Printf.printf "%d: %s\n" s#id s#title
  

This last solution has two big advantages: it provides a relatively
clean interface to users of the module, and allows for code reuse
without duplication.  Thanks to the way the object system in OCaml
works, the print_metadata function can operate on any objects that
have the #id and #title methods.  It feels almost like the duck-typing
present in languages such as Python (though different, of course).

However, I'm still not completely happy with it, mostly because the
hackery with the optional types inside the story class is ugly.  Does
someone have any clever ideas on how this could be modelled/improved?

Thanks,
Dario





      ___________________________________________________________
Yahoo! Answers - Got a question? Someone out there knows the answer. Try it
now.
http://uk.answers.yahoo.com/ 


^ permalink raw reply	[flat|nested] 55+ messages in thread
[parent not found: <47161E3B.3060704@tsc.uc3m.es>]

end of thread, other threads:[~2007-10-19 13:08 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-10-17 13:35 Smells like duck-typing Dario Teixeira
2007-10-17 14:13 ` [Caml-list] " Arnaud Spiwack
2007-10-17 14:47   ` Dario Teixeira
2007-10-17 14:25 ` Daniel Bünzli
2007-10-17 15:03   ` skaller
2007-10-17 15:13     ` Dario Teixeira
2007-10-17 15:25       ` Arnaud Spiwack
2007-10-17 15:32       ` Daniel Bünzli
2007-10-17 16:21         ` Chris King
2007-10-18  7:28           ` Stefano Zacchiroli
2007-10-18  8:33             ` [ANN] pa_oo and pa_polymap for 3.10 (Re: [Caml-list] Smells like duck-typing) Jacques Garrigue
2007-10-17 16:57         ` [Caml-list] Smells like duck-typing skaller
2007-10-17 16:52       ` skaller
2007-10-17 16:59         ` Robert Fischer
2007-10-17 14:33 ` Chris King
2007-10-17 14:59   ` Dario Teixeira
2007-10-17 15:24 ` Vincent Aravantinos
2007-10-17 15:26 ` Zheng Li
2007-10-18 16:13   ` Zheng Li
2007-10-18 16:37     ` [Caml-list] " William D. Neumann
2007-10-19  0:58       ` Jacques Garrigue
2007-10-17 19:59 ` [Caml-list] " Richard Jones
2007-10-17 20:24 ` Dario Teixeira
2007-10-18  7:37   ` Stefano Zacchiroli
2007-10-18 10:31     ` Dario Teixeira
2007-10-18 10:37       ` Stefano Zacchiroli
2007-10-18 13:28       ` Robert Fischer
2007-10-18 14:10         ` Dario Teixeira
2007-10-18 14:18           ` Brian Hurt
2007-10-18 14:29             ` Arnaud Spiwack
2007-10-18 14:45               ` Brian Hurt
2007-10-18 15:02                 ` Arnaud Spiwack
2007-10-18 15:07                   ` Robert Fischer
2007-10-18 15:14                     ` Arnaud Spiwack
2007-10-18 16:39                   ` skaller
2007-10-18 16:49                     ` Arnaud Spiwack
2007-10-18 17:47                       ` skaller
2007-10-18 19:55                         ` Robert Fischer
2007-10-18 16:22                 ` skaller
2007-10-18 16:30                   ` Dario Teixeira
2007-10-18 14:58           ` Robert Fischer
2007-10-18 15:11             ` William D. Neumann
2007-10-18 15:47               ` Loup Vaillant
2007-10-18 16:08                 ` William D. Neumann
2007-10-19 13:08               ` Ed Keith
2007-10-18 16:24           ` Dario Teixeira
2007-10-18 16:35             ` Vincent Aravantinos
2007-10-18 16:43             ` Brian Hurt
2007-10-18 17:04               ` William D. Neumann
2007-10-18 17:05               ` Dario Teixeira
2007-10-18 17:22                 ` Brian Hurt
2007-10-18 17:58                   ` Dario Teixeira
2007-10-18 15:42 ` Vincent Aravantinos
     [not found] <47161E3B.3060704@tsc.uc3m.es>
2007-10-17 15:01 ` Dario Teixeira
2007-10-17 20:20   ` Alain Frisch

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