Simulating call-by-reference with Dylan macros 
Author Message
 Simulating call-by-reference with Dylan macros

Quote:

> It seems to me that there are certain instances when "call-by-reference"
> is a handy feature that can make a program shorter and more elegant.  My
> question is this:  "Is there a way to simulate "call-by-reference" in
> Dylan?  (using macros perhaps)  When one wanted to "call-by-reference",
> you would use a different syntax:

>   Syntax for normal Dylan parameter passing:
>      increment(a);
>   Possible syntax for "call-by-reference" parameter passing:
>      increment(&a);

If you want call by reference in Dylan, you're out of luck.  (Though, as
this list may remember, some people think Dylan's call-by-value is
call-by-reference.  But enough on terminology...)

Macros can give you what you want, I think, except you get exactly the
same syntax for both types of parameter passing and there's a problem
with side-effects.

A simple macro for this purpose might be

  define macro increment
    { increment(?:expression, #key ?by:expression = 1) }
    => { ?expression := ?expression + ?by }
  end macro increment;

So, given this definition

  define method plus3(n)
    increment(n);
    increment(n, by: 2);
    n
  end method plus3;

plus3(1) should be 4, assuming I've remembered Dylan properly.

The problem is with side effects in the first parameter to increment.
A call to

  increment(a[i := i + 1])

would expand to

  a[i := i + 1] := a[i := i + 1] + 1

where what one wants is something closer to

  let index = (i := i + 1);
  a[index] := a[index] + 1;

Common LISP handles this problem (from memory) define-modifier-macro,
but Dylan really doesn't have an easy solution, as far as I know.

Paul



Fri, 12 Mar 1999 03:00:00 GMT  
 Simulating call-by-reference with Dylan macros

Quote:


> > It seems to me that there are certain instances when

"call-by-reference"

Quote:
> > is a handy feature that can make a program shorter and more elegant.

Although, as others pointed out, there are ways to "simulate" this, I would
like to hear a strong argument for "call-by-reference". Why is it useful
enough to warrant what I see as a very different view point about parameter
passing?

I can see how you'd rather write:

        increment(foo);

instead of:

        foo := increment(foo);

I find the former possibly easier to read and write, but is this really
worth introducing features to the language and potentially making
side-effects less apparent to the reader?

I'd like to add that except for this specific method on <number>, I don't
see the applicability for such a language feature. Note that I am not
arguing against "call-by-reference", but I would like to understand Peter's
above comment better.

...........................................................................
Chris Page
Software Wrangler                  This message was created using {*filter*}dog

http://www.*-*-*.com/ ~page/
...........................................................................



Fri, 12 Mar 1999 03:00:00 GMT  
 Simulating call-by-reference with Dylan macros

    "Chris> I can see how you'd rather write:

    "Chris>     increment(foo);

    "Chris> instead of:

    "Chris>     foo := increment(foo);

Although I'd rather write

                increment!(foo);

Andreas

--
... 31 seconds, and we're going ...



Sat, 13 Mar 1999 03:00:00 GMT  
 Simulating call-by-reference with Dylan macros

Quote:

> Although I'd rather write

>            increment!(foo);

Yes, although even with function names like "add!", the exclamation mark
only means that the object may be altered, but does not guarantee that it
will and you still have to assign the function result to the original
binding if you want the effect you're after. At least, that's the current
convention for "!".

...........................................................................
Chris Page
Software Wrangler                  This message was created using {*filter*}dog

http://www.*-*-*.com/ ~page/
...........................................................................



Sun, 14 Mar 1999 03:00:00 GMT  
 Simulating call-by-reference with Dylan macros

Quote:

> I think this may demonstrate when it can be handy.  I was writing a
little
> program to simulate a 8085 microprocessor.  I would have liked to create
a
> hash table for the instruction set as follows:

> define constant *instruction-table* = method ()
>    let the-table = make(<table>);
>    element-setter(MOV(*a*,*b*), the-table, #b01000000);
>    element-setter(MOV(*a*,*c*), the-table, #b01001000);
>    element-setter(MOV(*a*,*d*), the-table, #b01010000);
>    element-setter(MOV(*a*,*e*), the-table, #b01011000);
>                       .
>                            .
>                            .
>         element-setter(MOV(*h*,*l*), the-table, #b01011111);
>    the-table;
> end method ();

> where MOV copies a byte between registers with the
> arguments in the following order:  (destination-register,

source-register)

Assuming that what you desire to do is simulate the 8085 registers with
module variables (*a*, *b*, *c*, etc.), I think you would get what you want
with something like:

        define class <accumulator> (<object>)
                slot value :: <appropriate-integer-type>, init-value: 0;
        end class;

        define variable *a* = make(<accumulator>);
        define variable *b* = make(<accumulator>);
        [...]

        define method MOV (dest :: <accumulator>, source :: <accumulator>)
                dest.value := source.value
        end method;

IMHO, besides the fact that you probably want a mutable object and
<integer> is immutable, you should generally avoid using types like
<integer> directly, unless what you really want is an <integer> object. By
defining classes specific to your needs, you increase encapsulation and
type-safety. You also make your code more readable and your intentions
clearer.

In fact, I would create some kind of 8085 CPU class (e.g. <8085>), that has
slots for each register, instead of defining separate module variables.
Then I would define MOV on <8085>, allowing MOV to adjust other values in
the CPU as appropriate, such as carry and zero flags.

By the way, I ignored the fact that "MOV(*a*,*b*)" as used above will
probably not do what you want even if you have pass by reference because
MOV will be called and its value will be passed to element-setter. You'll
have to do something to delay evaluation of MOV and its parameters.

Quote:
> I think this may demonstrate when it can be handy.

Unfortunately, I don't think this example provides an argument (pardon the
pun) for pass by reference in Dylan. It appears to me that pass by
reference is simply an attempt to change a binding as a side effect, and I
don't see the utility of this. Why add mystery to your code by writing:

        m(foo);

instead of being explicit:

        foo := m(foo);

Also, It occurs to me that you may perceive variables to be objects. They
are not. They are bindings to objects (if I understand Dylan correctly).
Objects may be passed as parameters, but not bindings. Mutable objects,
passed to functions, may be changed, but not bindings.

What do you think?

...........................................................................
Chris Page
Software Wrangler                  This message was created using {*filter*}dog

http://www.*-*-*.com/ ~page/
...........................................................................



Thu, 18 Mar 1999 03:00:00 GMT  
 Simulating call-by-reference with Dylan macros

 ph> I think this may demonstrate when it can be handy.  I was writing a
 ph> little program to simulate a 8085 microprocessor.  I would have liked
 ph> to create a hash table for the instruction set as follows:

 ph> define constant *instruction-table* = method ()
 ph>         let the-table = make(<table>);
 ph>         element-setter(MOV(*a*,*b*), the-table, #b01000000);
 ph>         element-setter(MOV(*a*,*c*), the-table, #b01001000);
 ph>         element-setter(MOV(*a*,*d*), the-table, #b01010000);
 ph>         element-setter(MOV(*a*,*e*), the-table, #b01011000);
 ph>                            .
 ph>                            .
 ph>                            .
 ph>         element-setter(MOV(*h*,*l*), the-table, #b01011111);
 ph>         the-table;
 ph> end method ();

 ph> where MOV copies a byte between registers with the arguments in the
 ph> following order: (destination-register, source-register)

 ph> Now imagine a command similar to MOV, but with many more arguments and
 ph> more than one of the arguments affected by calling the function.
 ph> Wouldn't call-by-reference semantics would be very useful in that
 ph> case?

 ph> Of course the code above does not achieve the desired result due to
 ph> Dylan's argument passing semantics.  Maybe there is a better way to
 ph> tackle the problem, but I am missing it.

Why not define a class for registers, with a slot for the register value.
Then, you could make an instance of this class corresponding to each
register, and  modify the value in the slot to your heart's content.

Or am I missing it?

Don



Fri, 19 Mar 1999 03:00:00 GMT  
 
 [ 6 post ] 

 Relevant Pages 

1. Simulating call-by-reference with Dylan macros

2. Simulating call-by-reference in Ruby

3. Call by reference in Dylan

4. Simulating multi-dim array problem - OR - reference confusions

5. IV Called by reference doesn't open when called

6. are dylan macros Turing-complete?

7. C++ Templates used like Dylan Macros

8. C++ Templates used like Dylan Macros

9. Simple Reader Macros for Dylan

10. Simple Reader Macros for Dylan

11. dylan parser: Macros

12. Dylan program structure and macro parsing

 

 
Powered by phpBB® Forum Software