Version française
Home     About     Download     Resources     Contact us    
Browse thread
Instance variables can't be polymorphic?
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Zheng Li <zheng_li@u...>
Subject: Re: Instance variables can't be polymorphic? {a few more annoyances on "val" syntax}
Hello Jacques,

On 4/6/2009 5:40 AM, Jacques Garrigue wrote:
>
> Actually it's polymorphic, but only at the level of inheritance.
> You could define two objects inheriting from c, one using print_int,
> and the other print_string, and this would work.
>
> Due to functional update (i.e. {<  iter = ...>}), object-level
> polymorphism would have to be explicit, but as you pointed next, no
> syntax is provided for explicitly polymorphic fields.

Thanks for your clear explanation!

>> Trying to declare the polymorphism explicitly as
>>
>> --
>> val iter : 'a. ('a ->  unit) ->  'a list ->  unit = List.iter
>> --
>>
>> won't work. This syntax is only allowed for methods.
>
> Yes. It would be too difficult to add such a functionality, but what
> kind of application do you have in mind?

One of my project relies heavily on OO. We choose OO not in the 
traditional OO sense, but for the benefits of

   - structural subtyping
   - privileges control

The OO part is merely an "interface". The core is functional, and all 
the objects will be dropped right after the declaration/initialization 
phrase.

Here, selective access restriction of some data by declaring them as 
instance variable is just one way to control privilege, so that only 
objects of current class and its subclasses can access them. It's not 
100% safe since such objects can still expose the data again through 
public methods, however this will only happen when they really intend 
and take effort to make the mistake(?)

> The simplest way I see currently is to use a let defined field (i.e.,
> before the object keyword, but then you can't access it after
> inheritance), or to use a private method. What is your problem with a
> private method? It should be more flexible.
> Of course you can also define a record to wrap your polymorphic value.

Yes, private method is also the closest solution I could though of. 
"let" is not acceptable since the definition must be accessible through 
inheritance.

I preferred instance variable (if it could work in the same way) than 
private method since

  - it's more lightweight in syntax
  - it's more lightweight in execution cost
  - with instance variable, I can totally drop all objects right after 
the initialization; with private method, some part of the definition 
will still point back to objects since they contain self#xxx inside.

But anyway, assorting to private methods is still acceptable considering 
various aspects. I will probably take this approach.

[OT]: Here are a few more annoyances on the syntax of instance variable 
I've encountered. I recorded it here for comments:

Why it can't just copy the common "let" syntax in OCaml? Even though 
it's possible to just lift the awkward "val" definitions out of objects 
and using "let" instead, I'm really uncomfortable when being forced to 
do that. Besides, the lifted variables won't be accessible through 
inheritance any more, so they are not strictly equivalent or 
interchangeable in semantics.

Currently, the "val" syntax

- doesn't support pattern matching assignment. Instead of
   --
   let a,b,c,d = tuple4
   --
   one write
   --
   val a = match tuple4 with a,_,_,_ -> a
   val b = match tuple4 with _,b,_,_ -> b
   val c = match tuple4 with _,_,c,_ -> c
   val d = match tuple4 with _,_,_,d -> d
   --
   This is still the easy case, image if your pattern matching will also 
trigger some side-effect.

- doesn't support sharing state.
   --
   let up,down =
     let r = ref 0 in
     (fun () -> incr r; !r),
     (fun () -> decr r; !r)
   --
   can't be expressed directly as instance variables

- doesn't support shortcut syntax of function definition like
   --
   val f x y z = x + y + z
   --
   instead one must write
   --
   val f = fun x y z -> x + y + z
   --

- doesn't support recursion. Instead of
   --
   val rec fact n =
     if n <= 1 then 1 else n * fact (n-1)
   --
   one must write
   --
   val fact =
     let rec fact_rec n =
       if n <= 1 then 1 else n * fact_rec (n-1) in
     fact_rec
   --

- all parallel assignments, no assignment orders, hence can't refer to 
previous assignment

   --
   val x = 3
   val y = x + 11
   --

is wrong, even if it makes perfect sense in many situations. To access 
"x", one is simply forced to declare "y" as method!

Any comments?

--
Zheng