caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] RFC: get/set vs get/ref
       [not found]   ` <00a701c10a15$9b1db190$6701a8c0@abeast1.com>
@ 2001-07-12  1:49     ` John Max Skaller
  2001-07-14  3:10       ` Bruce Hoult
  2001-07-14  8:52       ` William Chesters
  0 siblings, 2 replies; 3+ messages in thread
From: John Max Skaller @ 2001-07-12  1:49 UTC (permalink / raw)
  To: boost, caml-list

[posted to caml-list@inria.fr and boost@yahoogroups.com]

I seek your opinion on  get/set vs. get/ref.

Suppose we desire to abstract an immutable data type.
We can do that by providing 'get' methods to access
the data. The canonical examples are

	a) tuples: represented by projection functions
	b) lists: represented by 'head' and 'tail' functions

When the data type is mutable, there are two choices.
The simplest choice is to provide set methods.
For example, for a mutable string, with C++ notation:

	char string::get_char (int pos) const
	void string::set_char (int pos, char ch)

For Algol like languages, we could also provide references:

	char string::get_char (int pos)const
	char &string::ref_char (int pos)

The difference is exemplified by the following techniques
for incrementing a character:

	s.set ((s.get(pos) + 1),pos)  // get/set method
	s.ref(pos).++                 // ref method

Clearly, ref methods are more powerful and more efficient,
but on the other hand they expose the underlying implementation
and prevent hooking changes to the mutable state.

What's the best technique?

-- 
John (Max) Skaller, mailto:skaller@maxtal.com.au 
10/1 Toxteth Rd Glebe NSW 2037 Australia voice: 61-2-9660-0850
New generation programming language Felix  http://felix.sourceforge.net
Literate Programming tool Interscript     
http://Interscript.sourceforge.net
-------------------
Bug reports: http://caml.inria.fr/bin/caml-bugs  FAQ: http://caml.inria.fr/FAQ/
To unsubscribe, mail caml-list-request@inria.fr  Archives: http://caml.inria.fr


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

* Re: [Caml-list] RFC: get/set vs get/ref
  2001-07-12  1:49     ` [Caml-list] RFC: get/set vs get/ref John Max Skaller
@ 2001-07-14  3:10       ` Bruce Hoult
  2001-07-14  8:52       ` William Chesters
  1 sibling, 0 replies; 3+ messages in thread
From: Bruce Hoult @ 2001-07-14  3:10 UTC (permalink / raw)
  To: John Max Skaller, boost, caml-list

At 11:49 AM +1000 7/12/01, John Max Skaller wrote:
>The difference is exemplified by the following techniques
>for incrementing a character:
>
>	s.set ((s.get(pos) + 1),pos)  // get/set method
>	s.ref(pos).++                 // ref method
>
>Clearly, ref methods are more powerful and more efficient,

I don't think that warrants a "clearly".  Given good compilers *both* 
will be compiled down to a memory load, an add, and a memory store.

For example, in Dylan you can do the following (Dylan source, 
followed by C generated by the Gwydion d2c compiler, followed by PPC 
asm):

---------------------------------
module: getset

define class <foo> (<object>)
   slot x :: <integer>,
     required-init-keyword: x:
end;

define function bar(s :: <foo>) => ()
   s.x := s.x + 1
end function bar;
---------------------------------
#define SLOT(ptr, type, offset) (*(type *)((char *)ptr + offset))

void getsetZgetsetZbar_FUN(descriptor_t *orig_sp, heapptr_t A_s /* s */)
{
     descriptor_t *cluster_0_top;
     long L_x; /* x */
     L_x = SLOT(A_s, long, 4);
     SLOT(A_s, long, 4) = (L_x + 1);
     return;
}
---------------------------------
0x29f4 <getsetZgetsetZbar_FUN>:     lwz     r9,4(r4)
0x29f8 <getsetZgetsetZbar_FUN+4>:   addi    r9,r9,1
0x29fc <getsetZgetsetZbar_FUN+8>:   stw     r9,4(r4)
0x2a00 <getsetZgetsetZbar_FUN+12>:  blr
---------------------------------



>but on the other hand they expose the underlying implementation
>and prevent hooking changes to the mutable state.

Right.  For example, in Dylan you can modify the above example to the 
following (Dylan source, generated C code for bar(), asm for bar(), 
output):

---------------------------------
module: getset

define function report(a :: <foo>, b :: <integer>) => ()
   format-out("slot x was %=, now %=\n", a.x, b);
end;

define class <foo> (<object>)
   slot x :: <integer>,
     required-init-keyword: x:,
     setter: internal-update-x;
end;

define inline method x-setter(new :: <integer>, a :: <foo>)
   report(a, new);
   internal-update-x(new, a);
end;

define function bar(s :: <foo>) => ()
   s.x := s.x + 1
end bar;

begin
   let a = make(<foo>, x: 13);
   bar(a);
end
---------------------------------
void getsetZgetsetZbar_FUN(descriptor_t *orig_sp, heapptr_t A_s /* s */)
{
     descriptor_t *cluster_0_top;
     long L_x; /* x */
     long L_new_value; /* new-value */
     L_x = SLOT(A_s, long, 4);
     L_new_value = (L_x + 1);
     getsetZgetsetZreport_FUN(orig_sp, A_s, L_new_value);
     SLOT(A_s, long, 4) = L_new_value;
     return;
}
---------------------------------
0x28bc <getsetZgetsetZbar_FUN>:         mflr    r0
0x28c0 <getsetZgetsetZbar_FUN+4>:       stmw    r28,-16(r1)
0x28c4 <getsetZgetsetZbar_FUN+8>:       stw     r0,8(r1)
0x28c8 <getsetZgetsetZbar_FUN+12>:      stwu    r1,-80(r1)
0x28cc <getsetZgetsetZbar_FUN+16>:      mr      r28,r4
0x28d0 <getsetZgetsetZbar_FUN+20>:      lwz     r29,4(r28)
0x28d4 <getsetZgetsetZbar_FUN+24>:      addi    r29,r29,1
0x28d8 <getsetZgetsetZbar_FUN+28>:      mr      r5,r29
0x28dc <getsetZgetsetZbar_FUN+32>:      bl      0x2590 
<getsetZgetsetZreport_FUN>
0x28e0 <getsetZgetsetZbar_FUN+36>:      stw     r29,4(r28)
0x28e4 <getsetZgetsetZbar_FUN+40>:      lwz     r0,88(r1)
0x28e8 <getsetZgetsetZbar_FUN+44>:      addi    r1,r1,80
0x28ec <getsetZgetsetZbar_FUN+48>:      mtlr    r0
0x28f0 <getsetZgetsetZbar_FUN+52>:      lmw     r28,-16(r1)
0x28f4 <getsetZgetsetZbar_FUN+56>:      blr
---------------------------------
[localhost:~/programs/dylan/getset] bruce% ./getset
slot x was 13, now 14
---------------------------------



>What's the best technique?

get/set, I think.

With appropriate language support it can:

- have exactly the same syntax as traditional languages, with no ugly 
function notation for things that users think of as fields

- compile down to the exact same code that would be generated by 
languages such as C

- have the ability to transparently hook extra functionality such as 
format changes, monitoring, filtering into the getter and/or setter 
with no changes to the client code.


Sorry to post Caml-free stuff here :-(

-- Bruce
-------------------
Bug reports: http://caml.inria.fr/bin/caml-bugs  FAQ: http://caml.inria.fr/FAQ/
To unsubscribe, mail caml-list-request@inria.fr  Archives: http://caml.inria.fr


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

* [Caml-list] RFC: get/set vs get/ref
  2001-07-12  1:49     ` [Caml-list] RFC: get/set vs get/ref John Max Skaller
  2001-07-14  3:10       ` Bruce Hoult
@ 2001-07-14  8:52       ` William Chesters
  1 sibling, 0 replies; 3+ messages in thread
From: William Chesters @ 2001-07-14  8:52 UTC (permalink / raw)
  To: caml-list

John Max Skaller writes:
 > The difference is exemplified by the following techniques
 > for incrementing a character:
 > 
 > 	s.set ((s.get(pos) + 1),pos)  // get/set method
 > 	s.ref(pos).++                 // ref method
 > 
 > Clearly, ref methods are more powerful and more efficient,
 > but on the other hand they expose the underlying implementation
 > and prevent hooking changes to the mutable state.

I was a little disappointed that while ocaml compiles the "bare"
increment case right,

    a.(i) <- a.(i) + 1   =>   addl $2, -2(%eax, %ebx, 2)

it doesn't do such a good job on 

    let set s i y = s.a.(i) <- y and get s i = s.a.(i)
    in
    fun s i -> set s i ((get s i) + 1)

      =>

      movl    (%eax), %ecx
      movl    -2(%ecx, %ebx, 2), %ecx
      addl    $2, %ecx
      movl    (%eax), %eax
      movl    %ecx, -2(%eax, %ebx, 2)

apparently because of the lack of common subexpression elimination
(the CS here being `s.a').  The argument against CSE seems to be that
it doesn't do anything the programmer can't do for themselves,
probably with a net gain in readability, if they really care.  But
I have seen several examples like Max's where it would actually help
in reducing the cost of crossing an abstraction barriers.

(By the way, KAI's famous optimising C++ actually INTRODUCES common
subexpressions and leaves them for the platform C backend to
eliminate!  If you define a variable using a const expression and
never modify it, it goes through substituting the expression wherever
the variable appears.  The idea I suppose is to create opportunities
for constant folding etc.  But it is extremely frustrating with gcc,
which doesn't always do the expected CSE completely---there is
absolutely no way to work around it short of introducing a spurious
global reference to the variable.  This is an example of over-complex
and unpredictable optimisation making trouble for the programmer.

Nevertheless I do think a little more support in ocaml for cost-free
abstractions would be a win.)

-------------------
Bug reports: http://caml.inria.fr/bin/caml-bugs  FAQ: http://caml.inria.fr/FAQ/
To unsubscribe, mail caml-list-request@inria.fr  Archives: http://caml.inria.fr


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

end of thread, other threads:[~2001-07-14  8:51 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <Pine.LNX.4.33.0107110922490.1683-100000@localhost.localdomain>
     [not found] ` <0107111558020P.12210@baxter>
     [not found]   ` <00a701c10a15$9b1db190$6701a8c0@abeast1.com>
2001-07-12  1:49     ` [Caml-list] RFC: get/set vs get/ref John Max Skaller
2001-07-14  3:10       ` Bruce Hoult
2001-07-14  8:52       ` William Chesters

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