* 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