* [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