Almost through the book.....now questions.... 
Author Message
 Almost through the book.....now questions....

ALERT: I am NOT ragging on Dylan.  I have not even begun to use it, but I do
have some questions that have come to me as I was reading the book (Dylan
Programming:...).

I expected generic functions to take into count the number of required
[,non-keyword (?)] arguments.
Example:
   define method foo (x :: <integer>, y :: <integer>) ....
and
   define method foo (z :: <integer>) ....

Coming from a C++ and Ada point of view those are different functions that
only happen to have the same name; their signatures are different. Was this
just for purity such that "foo" means the same generic function each time it
is mentioned.

Since the exported bindings in a module become visible to an importing
module, and there can be no duplicates among the binding names visible to a
module, doesn't this cause problems in larger systems?  C had this problem
that C++ fixed with the introduction of namespaces.  C systems use naming
conventions to prevent name clashes such as a "module" prefix on function
names.  Is this what is done in Dylan systems? Seems kind of limiting, but
again maybe this is just part of the "purity" of names in Dylan. "foo" is
"foo" everywhere in the program (unless of course it's private to me and I
can't see another "foo" or I saw one and I renamed it when I imported it).

The dot-syntax.
x.foo is the same as foo(x).  I'm surprised that this syntax was not
extended to methods taking more than one argument.  Example: foo(x, y, z)
could be written z.foo(x, y). So "x.foo" and "x.foo()" would just be a
specific case of taking the last argument and moving it out to the front
before the dot.

Limited Integer types.
I'm surprised that limited(<integer>, min:0) doesn't imply runtime checks to
verify the value of what is getting assigned.
Example:
define variable *my-limited-int* :: limited(<integer>, min:0, max: 40) = 0;
*my-limited-int* := -5; /* This would cause a runtime error */
Obviously this kind of checking has a severe effect on runtime performance.
That is why systems that support something along this notion (Eiffel
preconditions and Ada range constraints) provide a way to turn off the range
checking in a "finalized" or "release" compilation.  It seems that this is
something that a compiler maker could do that would not change the language,
but could be of great assistance in helping developers write safer programs.

Please, I've been learning Dylan now for....oh...4 days, so be kind when
pointing out my ignorance.

Michael Garnett



Wed, 31 Oct 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Quote:

>I expected generic functions to take into count the number of required
>[,non-keyword (?)] arguments.
>Example:
>   define method foo (x :: <integer>, y :: <integer>) ....
>and
>   define method foo (z :: <integer>) ....

>Coming from a C++ and Ada point of view those are different functions that
>only happen to have the same name; their signatures are different. Was this
>just for purity such that "foo" means the same generic function each time it
>is mentioned.

The technical term for "different functions that only happen to have the
same name but different signatures" is overloading.  Ada and C++ have this,
but Dylan has chosen not to.  If something is a different function, it
deserves a name of its own.  I've noticed that C++ programmers get
extremely confused between overloading and member selection.

Furthermore, things get very tricky when you add optional arguments into
the mix.  If your second method took an optional integer argument, foo(1,
2) would be ambiguous.

Quote:
>The dot-syntax.
>x.foo is the same as foo(x).  I'm surprised that this syntax was not
>extended to methods taking more than one argument.  Example: foo(x, y, z)
>could be written z.foo(x, y). So "x.foo" and "x.foo()" would just be a
>specific case of taking the last argument and moving it out to the front
>before the dot.

It seems strange that you would suggest the *last* argument be moved out.
I think most would expect it to be x.foo(y, z).

The reason this isn't done is because with multi-methods there's no reason
to single out a specific argument to be pulled out.  If you have a
display(output-device, shape) generic function, why should it be
shape.display(output-device) rather than output-device.display(shape)?

Quote:
>Limited Integer types.
>I'm surprised that limited(<integer>, min:0) doesn't imply runtime checks to
>verify the value of what is getting assigned.
>Example:
>define variable *my-limited-int* :: limited(<integer>, min:0, max: 40) = 0;
>*my-limited-int* := -5; /* This would cause a runtime error */
>Obviously this kind of checking has a severe effect on runtime performance.
>That is why systems that support something along this notion (Eiffel
>preconditions and Ada range constraints) provide a way to turn off the range
>checking in a "finalized" or "release" compilation.  It seems that this is
>something that a compiler maker could do that would not change the language,
>but could be of great assistance in helping developers write safer programs.

I expect that some of them do, just as there are C development environments
that will detect memory allocation problems.  There's no need for it to be
in the language.

--

GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.



Wed, 31 Oct 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Quote:

> Example:
>    define method foo (x :: <integer>, y :: <integer>) ....
> and
>    define method foo (z :: <integer>) ....

This is not allowed and and to me it is a good thing because it means that
for methods that are supposed to perform the equivalent action (and are
thus named the same), each parameter has the equivalent meaning, position
by position.

Dylan's keyword parameters give you the flexibility you need to specify
optional parameters.  Once you get used to using keyword parameters, I
doubt if you will miss C++ style overloading, and will probably begin to
regard it as a ugly kludge.

Quote:

> Since the exported bindings in a module become visible to an importing
> module, and there can be no duplicates among the binding names visible to a
> module, doesn't this cause problems in larger systems?

No, I don't think it is going to be a problem.  Generally you don't import
binding which you don't need into a module.  Also you can rename binding
if necessary.  Also, the more verbose naming style in Dylan reduces the
chance of clashes.  

Quote:

> Limited Integer types.
> I'm surprised that limited(<integer>, min:0) doesn't imply runtime checks to
> verify the value of what is getting assigned.
> Example:
> define variable *my-limited-int* :: limited(<integer>, min:0, max: 40) = 0;
> *my-limited-int* := -5; /* This would cause a runtime error */

It should cause a runtime error, and does in Gwydion Dylan:
  -5 is not of type {limited fixed integer 0<=x<=40}

It is my understanding that the Harlequin Dylan interactive listener does
not always do the type checking that it should.  Are you using the
listener or is the code in a file?

regards

--------------------------------------------------------------------

Dylan... the high-performance dynamic language
 * open-source Unix version:  http://www.gwydiondylan.org/
 * free Win32 version: http://www.harlequin.com/products/ads/dylan/
---------------------------------------------------------------------



Wed, 31 Oct 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Quote:

> It is my understanding that the Harlequin Dylan interactive listener does
> not always do the type checking that it should.  Are you using the
> listener or is the code in a file?

I tried it with HD in production mode in a file (ie. no
listener). Using 'define variable' to define the variable like:

define variable *my-limited-int* :: limited(<integer>, min: 0) = 5;
*my-limited-int* := -5; // (1)

Gives a compile time warning on line (1):

"Illegal assignment of variable "*my-limited-int*" of type
{model-object :: <limited-integer>} to -5."

It also gives a run time warning if run. Strangly though, the
following does not produce any errors, run time or compile time:

begin
  let my-limited-int :: limited(<integer>, min: 0) = 5;
  my-limited-int := -5
end;

Chris.



Thu, 01 Nov 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Quote:


>> It is my understanding that the Harlequin Dylan interactive listener does
>> not always do the type checking that it should.  Are you using the
>> listener or is the code in a file?

Oh, yes.  I *am* using the listener.  Well, that makes me happier to see
that it produces those errors.

Quote:
>begin
>  let my-limited-int :: limited(<integer>, min: 0) = 5;
>  my-limited-int := -5
>end;

Do you think they omit the runtime checks for local variables?  Interesting
optimization.

Michael G.



Thu, 01 Nov 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Quote:

> Furthermore, things get very tricky when you add optional arguments into
> the mix.  If your second method took an optional integer argument, foo(1,
> 2) would be ambiguous.

Which, by the way, is similar to the case where you have #key and #rest arguments
at the same time - allowed but not very helpful.

HW
--
Phone: +41-1-2348754
Fax: +41-1-2364671

Web: http://www.ubs.com/ubilab



Fri, 02 Nov 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Quote:

> Dylan's keyword parameters give you the flexibility you need to specify
> optional parameters.  Once you get used to using keyword parameters, I
> doubt if you will miss C++ style overloading, and will probably begin to
> regard it as a ugly kludge.

Disagreed. It's helpful, and I never had any problems with its semantics.

Keywords are a perfect solution if (and only if) you want to evolve the argument
list without letting the methods of a generic function know that happens. Best
example: Dylan's instantiation protocol, i.e. make() and initialize(). Have a look
at the Anything pattern (Sommerlad and Ruedi) in EuroPLoP 98.

C++ style overloading is *not* used for this purpose, but rather to make the code
look neat (syntactic sugar). There is no added value in terms of program behavior.
C++ sort of has typed name spaces, where "type" refers to the function signature.
I always found this intuitive. Others might not, but it's surely not an ugly
kludge.

Some, by the way, use keywords to document code in the style of:

begin
  let p = point(x: 100, y: 300);
end;

instead of:

begin
  let p = point(100, 300);
end;

It is immediately clear point() doesn't take y=100 and x=300 but vice versa. You
can do this, but you lose type safety (e.g., missing parameters are not caught at
compile time). Keep in mind that here you trade safety against elegance or
intelligibility. In C++ style overloading you trade elegance against
intelligibility while the level of type safety remains the same.

I always found C++ overloading is truly superior to Dylan. However, I still prefer
Dylan over C++ for other obvious reasons.

Regard it as different solutions to different problems :-)

HW
--
Phone: +41-1-2348754
Fax: +41-1-2364671

Web: http://www.ubs.com/ubilab



Fri, 02 Nov 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Quote:


> > Dylan's keyword parameters give you the flexibility you need to specify
> > optional parameters.  Once you get used to using keyword parameters, I
> > doubt if you will miss C++ style overloading, and will probably begin to
> > regard it as a ugly kludge.

> Disagreed. It's helpful, and I never had any problems with its semantics.

Okay, let me give an example.  In Java, there are seven different forms of
constructors for String.  Likewise, the Thread constructor has 7 forms.
How does one remember which argument goes where?  It's not easy to
remember the order of the arguments without a reference card.  (There may
be even more extreme examples in some of the new Java libraries, I'm not
sure.)

Quote:
> Keywords are a perfect solution if (and only if) you want to evolve the
argument
> list without letting the methods of a generic function know that happens. Best
> example: Dylan's instantiation protocol, i.e. make() and initialize().
Have a look
> at the Anything pattern (Sommerlad and Ruedi) in EuroPLoP 98.

> C++ style overloading is *not* used for this purpose, but rather to make
the code
> look neat (syntactic sugar). There is no added value in terms of program
behavior.
> C++ sort of has typed name spaces, where "type" refers to the function

signature.

I don't see the distinction you are making.  Both routes (C++ style
overloading or Dylan style keyword arguments) aim to give methods with
similar functionality the same name in order to make code more readable.
But I think one route is clearly more readable than the other.

Quote:

> It is immediately clear point() doesn't take y=100 and x=300 but vice
versa. You
> can do this, but you lose type safety (e.g., missing parameters are not
caught at
> compile time). Keep in mind that here you trade safety against elegance or
> intelligibility. In C++ style overloading you trade elegance against
> intelligibility while the level of type safety remains the same.

I think you are confusing orthogonal issues.  A language could support
required keyword parameters that had type specifications.  (Anything that
can be done with positional arguments can be done with keyword arguments.)

Dylan does have required keyword parameters for some methods (the
required-init-keyword slot specification ), though you can't specify type
contraints for them.

--------------------------------------------------------------------

Dylan... the high-performance dynamic language
 * open-source Unix version:  http://www.gwydiondylan.org/
 * free Win32 version: http://www.harlequin.com/products/ads/dylan/
---------------------------------------------------------------------



Fri, 02 Nov 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Quote:

> About typed keywords: the only advantage they give over required arguments is
> documentation (see below) and not having to care about ordering. So far,

so good.

This documentative capability of keyword arguments is very handy in some
places.  This method definition is from one of my programs:

define method calculate-bandwidth (#key big-size :: <integer>,
                                        small-size :: <integer>,
                                        big-rtt :: <float>,
                                        small-rtt :: <float>)

If I used positional arguments, there was a big chance that I would get
the order of the arguments confused in the calling code, so I decided to
go with all keyword arguments.

Quote:

> But maybe I'm missing someone's point here. Who actually uses keywords
> in other places than object creation?

Keyword arguments are common in Dylan code.  In my code, a lot of the
functions which I define have them.

--------------------------------------------------------------------

Dylan... the high-performance dynamic language
 * open-source Unix version:  http://www.gwydiondylan.org/
 * free Win32 version: http://www.harlequin.com/products/ads/dylan/
---------------------------------------------------------------------



Sat, 03 Nov 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Quote:

> Okay, let me give an example.  In Java, there are seven different forms of
> constructors for String.  Likewise, the Thread constructor has 7 forms.
> How does one remember which argument goes where?

As I said, some might find this confusing, it's a matter of personal taste. But I
have *never* ever had problems of that sort, including code others had written. It's
not too balanced to state C++ is ugly when you *personally* find it confusing. Or
say so. As a counterexample, what value would there be in having to write something
like this:

     String foo = new String((new Integer(42)).toString());

just because you can't create a String directly from an int but only from another
String? I find this rather suboptimal (and an ugly kludge, too ;-).

About typed keywords: the only advantage they give over required arguments is
documentation (see below) and not having to care about ordering. So far, so good.
But then: tell me how to control the consistency of a large system with extensive
use of keywords. Such stuff is *extremely* hard to test. Checked arguments are
indispensable to keep the complexity low. It is not a panacea, but it helps a lot.
And in this regard it's *definitely* superior to keywords.

Quote:
> I think you are confusing orthogonal issues.  A language could support
> required keyword parameters that had type specifications.  (Anything that
> can be done with positional arguments can be done with keyword arguments.)

Of course you can do that. The example I gave meant to illustrate that using keyword
arguments helps document your code. Nothing else. I made a point in praise of
keywords.

Please don't get me wrong, I'm using keywords myself. But *only* for evolution
purposes. If you want to use them to document your code, feel free to do so, I do
not. If you think C++ style overloading is confusing, don't use it. I'm fine with it
and I won't complain if others are not.

But maybe I'm missing someone's point here. Who actually uses keywords in other
places than object creation? What's the added value over checked arguments a la C++?
That I'd love to learn about.

HW
--
Phone: +41-1-2348754
Fax: +41-1-2364671

Web: http://www.ubs.com/ubilab



Sat, 03 Nov 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Quote:

> ...
> Dylan does have required keyword parameters for some methods (the
> required-init-keyword slot specification ) ...

Yep, you can only have required keywords for classes (that is, for
calls to make and initialize), which is a rare example of "magic" in
Dylan.  Keywords mentioned in the definition of a generic function
are termed "mandatory", but they're required in related method
definitions, not in related calls.  I'm sure there's been some
discussion (internal to Harlequin) about what the consequences might
be, of allowing required keywords for any functions, but I can't
remember much about them offhand.

Quote:
> ... though you can't specify type contraints for them.

Yes, you can; e.g.,

  define class <my-class> (<object>)
    slot foo :: <integer>;
    required keyword foo:, type: type-union(<string>, <integer>);
  end class;

  define method make
      (class :: subclass(<my-class>),
       #rest init-args,
       #key foo :: type-union(<string>, <integer>), #all-keys)
   => (instance :: <my-class>)
    let foo-integer :: <integer>
      = if (instance?(foo, <string>))
          string-to-integer(foo)
        else
          foo
        end;
    apply(next-method, class, foo: foo-integer, init-args)
  end method;

(untested).



Sat, 03 Nov 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Quote:

> Please don't get me wrong, I'm using keywords myself. But *only* for
> evolution purposes.

Ah, as an aside: you can also use one <object> as argument type and
downcast it to the type of argument list you need, e.g.

     define class <point-args> (<object>)
       slot x :: <integer>, init-value: 0;
       slot y :: <integer>, init-value: 0;
     end;

and then write:

     let p = point(make(<point-args>, ...));

And you won't need keywords to evolve your system. (Disregarding the
fact that of course make() takes keyword arguments.) But this approach
has it's downsides, too, e.g. object bloat.

HW
--
Phone: +41-1-2348754
Fax: +41-1-2364671

Web: http://www.ubs.com/ubilab



Sat, 03 Nov 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Doesn't

  define method foo (#key bar :: <bletch>) ... end;

essentially make bar a "required" keyword, since if you omit it, it will be bound to #f which is not a <bletch>?  [Assuming instance?(<bletch>, #f) == #f.]



Sat, 03 Nov 2001 03:00:00 GMT  
 Almost through the book.....now questions....


Quote:
>Doesn't

>  define method foo (#key bar :: <bletch>) ... end;

>essentially make bar a "required" keyword, since if you omit it, it will be
>bound to #f which is not a <bletch>?  [Assuming instance?(<bletch>, #f) ==

#f.]

Only in a "side-effect" sort of way.  For one thing, I suspect
implementations would give you different errors for "required keyword
missing" and "incorrect type for keyword".  From a more formal point of
view, you might want to require a keyword whose value could be of any
particular type (including <object>), which your method [pun intended ;-)]
doesn't allow.

Hugh G. Greene



Sat, 03 Nov 2001 03:00:00 GMT  
 Almost through the book.....now questions....

Okay, how about:

define macro required-keyword
  required-keyword(?name) => error("Missing required keyword: " ## ?"name")
end;

define method foo (#key bar :: <bletch> = required(bar)) ... end;

[I'm sure I wrote the macro incorrectly, but I think you get the idea.]



Sat, 03 Nov 2001 03:00:00 GMT  
 
 [ 24 post ]  Go to page: [1] [2]

 Relevant Pages 

1. (almost) Free Forth book!

2. almost dyadic iota, but not quite

3. I'm almost afraid to ask about (improved J Jacobi method)

4. component files (almost) for J Freeware

5. gsub variables - I'm almost there

6. CSS Editor almost ready

7. TDK locks global properties (almost always).

8. ABC Browse almost fixed

9. Clarion almost looks error free

10. iForth 2.0 is (almost) out

11. almost standard W@

12. Clip5.3b - Almost There !!

 

 
Powered by phpBB® Forum Software