Version française
Home     About     Download     Resources     Contact us    
Browse thread
Re: Syntax for label
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Pierre Weis <Pierre.Weis@i...>
Subject: Re: Syntax for label, NEW PROPOSAL
> > Thus, I would prefer to discuss deeper and more semantic problems:
> > 
> > -- Problem1: labels can be reserved keywords. This is questionable
> > and it has been strongly criticised by some Caml users, especially when
> > reading in the code the awful sequence fun:begin fun ...
> Well, maybe just because I've grown used to it, I do not find it awful
> at all.

At least more verbose than (fun ) or f (if the function is named as I
would recommend to any programmer that is fond of readability).

> The rationale behind allowing the use of keywords as labels is that
> there are lots of keywords in Caml, and many of them are good
> candidates for labels. Not allowing them makes often choice more
> difficult, or forces to use longer names.

The problem is that we have just a few rule for the Caml syntax, and
this violates this elementary one:

``In Caml, keywords are RESERVED identifiers''

Following this rule, we cannot use keywords as identifiers, even if it
would be very convenient ones such as ``val'' and, even if there is no
syntactic ambiguity, ``val'' is not allowed in patterns.

> This would mean:
> fun -> func

Could also consider fn


> Beware however that label changes are inherently dangerous: you often
> realize afterwards that a choice was not so good, and I really hoped
> that we could definitively fix the standard library labels in 3.00.
> > -- Problem2: labels that spread all over the standard libraries, even
> > when they do not add any good.
> Well, the current policy (as defined in the manual) is to put labels
> on at least all arguments but one (with some very special exceptions
> like printf). This is necessary to allow commuting between arguments,
> which is also an important theme of labels. As such I would not say
> that they do not do any good.

I'm afraid I don't agree with you: commuting between arguments is not
worth the extra burden of having labels, I'm not sure it is even
desirable. I think that when arguments of a function are not always
passed in the same order the readibility of the code is jeopardized.

> > I would cite:
> > 
> >    * the labels completely redundant with the types
> >      (E.g. char:char in the type of String.contains or String.index)
> Following the above policy, I would say that these are not ideal
> choices, but then what other possibility is there?

Remove the label.

> Moreover, even if this label is redundant in types, it is not
> necessarilly so in code.

May be not redundant, we can say useless or nocive ?

> >    * undesired labels: in many cases I don't want to have labels just
> >      because I don't want to remember their names. (E.g., I very often
> >      mispell the label acc since I've always used accu to name an
> >      accumulator; furthermore, when I do not mispell this label, I feel
> >      acc:accu extremely verbose). Also because labels are verbose at
> >      application.
> Isn't there a classic mode for that?
> If you think that labels are verbose, you can use it, and it even
> provides some partial support for label checking when you want it.

If we must always use the no modern option of the compiler, I think
there is some kind of drawback in the label world...

> I suppose we should have a precise idea of what labels are there for.
> For me they are a systematic mechanism, and the fact we allow to have
> no label on one argument in function types is just a little comfort,
> particularly useful when working with functionals.

Wao! So, the normal evolution would be to have labels as ``a
systematic mechanism'' ? I'm afraid this is really a dogmatic view,
and may be some Caml users will object ...

> >    * labels that prevent you to use comfortably your traditional functions.
> >      This is particularly evident for the or List.fold_right
> >      higher-order functionals.
> > 
> > This last point is a real problem. Compare the usual way of using
> > functionals to define the sum of the elements of a list:
> > 
> > # let sum l = List.fold_right ( + ) l 0;;
> > val sum : int list -> int = <fun>
> Whether you consider this readable or not is a question of taste.  I
> personally believe that you need quite a background in HO formalisms
> to understand the above. But of course most current Caml users have
> this background.

No, this is not a question of taste, since whatever readable you
consider this definition, it is still more readable, easier to
understand and easier to write than the labelized version:

let sum = List.fold_right fun:begin fun x acc:y -> x + y end acc:0;;

> > # let sum l = List.fold_right ( + ) l 0;;
> >                               ^^^^^
> > This expression has type int -> int -> int but is here used with type 'a list
> Aargh, that's right, error messages are a pain. I believe I worked a
> lot making them informative, but there are still difficult situations.
> I'll try to improve this.
> Remark however that, in modern mode, it is already strange to have an
> application with no labels at all...

Aargh, is that the future of Caml programming, as the ``modern'' flag
tends to suggest ? :(

> > The real problem is that fixing the code makes no good at all to its
> > readability (at least that's what I would say):
> > 
> > # let sum = List.fold_right fun:begin fun x acc:y -> x + y end acc:0;;
> > val sum : 'a -> int list -> int = <fun>
> You do not have to use begin .. end everywhere.
> I do personally write:
> # let sum = List.fold_right acc:0 fun:(fun x :acc -> x + acc);;

Hum... I do personnaly got this idea by reading the code from the files,,,, ..., in the
directory otherlibs/labltk/browser/ of the compiler distribution.

> Remark that here you didn't care about whether acc is the first or
> second argument of the passed function, just because (+) is
> commutative. However, in general functions are not commutative, and I
> always have to think a lot when using List.fold_left or
> List.fold_right without labels, just because I may write wrong code
> without the type checker telling me anything.

Yes functions in general are not commutative, but I cannot imagine how
labels may prevent you from thinking when using List.fold_right...

> > For all these reasons, I would suggest to carefully use labels into
> > the standard libraries: 
> > 
> > -- remove labels from higher-order functional
> > -- remove redundant labels: when no ambiguity can occur you need not
> >    to add a label.
> > -- use labels when typechecking ambiguity is evident (for instance
> > when there are two or more parameters with the same type).
> > 
> > Labels must enforce readability of code or help documenting the
> > libraries, it should not be an extra burden to the programmer and a
> > way of offuscating code.
> This seems to boil down to using labels for documentation purposes
> only. If you reduce them to such an extent, I'm afraid they will not
> do very much for code readability anymore. And I stated above, you get
> typechecking holes in functionals.

Do you suggest the current version of Objective Caml comes with a
typechecker that gives you ``holes in functionals'' ?

> By the way, I do not see how labels can help obfuscating code.

In several ways, I think labels may help obfuscating code, for
instance if they allows you to treat the arguments of functions as a
set instead of an ordered list: if arguments are never passed in the
same order, the code is much harder to read, since it is much more
difficult to remember the profile of functions (unless you remember
the set of labels associated with the function's profile AND the types
associated with the labels).

> What you are probably intending to say is that they make more
> difficult to write some combinator-based HO-style code. Does it mean
> we should have a version of the List module without labels for such
> uses?

You said so.

> > Evidently, as any other extension, labels must not offuscate the
> > overall picture, that is they must not clobber the semantics, nor add
> > extra exceptional cases to the few general rules we have for the
> > syntax and semantics of Caml.
> > 
> > In this respect, optional labelled arguments might also be discussed,
> > particularly for the following facts:
> > 
> > -- syntactically identical patterns and expressions now may have
> > incompatible types:
> >    # let f ?style:x _ = x;;
> >    val f : ?style:'a -> 'b -> 'a option = <fun>
> > 
> >    As a pattern on the left-hand side x has type 'a, while as an
> >    expression on the right hand side it has type 'a option
> Well, internally the left-hand side is also 'a option, but option is
> abbreviated because it is redundant. I do not think people want to see
> the left-hand side option, but maybe this technical part should be
> made more explicit in the manual.

This is not the problem: the problem is this is an exception to a simple
and intuitive rule of the Caml static semantics:

``In Caml, variables bound by patterns have a unique type''

Corollary: when used in expressions, variables bound by patterns have
the same type as their pattern type.

> Conversion from 'a to 'a option is done at application. I do not
> think there is any semantical problem here.

I do think there is a problem here, since once more this violates a
simple rule of Caml semantics:

``In Caml, there is no implicit coercions.''

Admittedly, this is a burden for arithmetic operations, but this is
also extraordinarily simple to explain and understand.

> > -- some expressions can be only written as arguments in an application
> >    context:
> >    # let f ?style:x g = ?style:x;;
> ?style:x is not an expression: labels are part of the application
> node, not of the arguments.

I know that and find it counter-intuitive, since once more it breaks
a very simple and intuitive rule of Caml:

``Caml expressions possess the sub-term property: sub-expressions are
also expressions''

(Hence, if e1 e2 is an application, then e1 and e2 are valid expressions).

> > -- the simple addition of a default value to an optional argument may
> >    trigger a typechecking error:
> > 
> >    # let f ?(style:x) g = g ?style:x;;
> >    val f : ?style:'a -> (?style:'a -> 'b) -> 'b = <fun>
> > 
> >    # let f ?(style:x = 1) g = g ?style:x;;
> >    This expression has type int but is here used with type 'a option
> That one is more serious. This is not a "simple addition". Default
> values unroll some syntactic sugar, changing the type of the
> argument.

Once more, I know those technical reasons, but I do not get for
granted that technical reasons are a valid answer to violations of the
simplicity and intuitive understanding of the language. If technical
reasons cannot handle some nice feature but force you to turn this
feature into a bad hack, then you must choose not to incorporate the
feature since it is no more a nice feature.

> Whether this is a good idea to have such syntactic sugar in
> the language is an interesting question. However I believe it provides
> some real comfort.

You must carefully balance this comfort with the extra cost in terms
of complexity and exceptions to the usual semantics (either static or
dynamic) ...

> > Do not forget the design decision that has always been used before in
> > the development of Caml: interesting but not universal extensions to
> > the language must carefully be kept orthogonal to the core language
> > and its libraries. This has been successfully achieved for the
> > important addition of modules (that do not prevent the users from
> > using the old interface-implementation view of modules) as well as for
> > the objects system addition that has been also maintained orthogonal
> > to the rest of the language (in particular the standard library has
> > never been ``objectified''). I don't know of any reason why labels
> > cannot follow the same safe guidelines.
> I just believed that it was agreed that labelizing the standard
> library was a progress.

It can be a progress if labels are introduced when they avoid
some (common) errors or ambiguities.

> A first approach would be to say that one can always use classic mode.
> Modern is not pedantic, it is just another typing discipline.
> But this would endanger the unicity of the language, so this cannot be
> an universal answer.

You're right, so we still have to think hard on the subject, and try
not to violate the few intuitive rules we have in Caml.

> Now, the problem we are talking about seems to boil down to higher
> order functions in modern mode. And more particularly List.fold_left
> and List.fold_right, since these are about the only two functions
> where the argument itself has labels.
> It would cost nothing to add 4 more unlabelled functions to the List
> module.

And do the same for modules List and Hashtbl and Array and Set and
Map, ... this will cost a bit I think.


> One may even insist that fun: is superfluous.
> Then it would probably be better to have another List module without
> labels at all. Again, this is pretty easy to do, and does not incur
> any code blow in general.
> Or do you think that the problem is deeper, and that labels are
> breaking the foundations of the language ?

In my opinion some fundamental rules are broken in the current
situation of the labels addition, and I think we should try to
overcome this drawback to let the language simple to explain and use.

Pierre Weis

INRIA, Projet Cristal,