## Re: "ocaml_beginners"::[] Coding style: let vs and

Expand Messages
• My (admittedly unjustified) personal style is to use let .. in , except for mutual recursive bindings let rec .. and .. . I m not fond of using let..and
Message 1 of 13 , Feb 15, 2012
My (admittedly unjustified) personal style is to use "let .. in",
except for mutual recursive bindings "let rec .. and ..". I'm not fond
of using let..and directly as it adds an uncertainty on evaluation
effect order, and -- to me -- suggest mutual dependency rather than
non-dependency. For short, clearly effect-free bindings, I actually
write "let x,y = foo,bar" rather than "let x = foo and y = bar".

For the evaluation-order effect, consider this `map` function on binary trees:

let rec map f= function
| Leaf -> Leaf
| Branch(a, x, b) ->
let fa = map f a and fb = map f b in
Branch(fa, f x, fb)

This definition has the downside that `f` is applied in a fairly
unpredictable, unspecified and unsatisfying order. While I don't want
to encourage users into using `map` with weird effectful functions
relying on evaluation order, I found it to be less painful for both me
and them if their evil trickeries will actually work in the way they
expect (left to right), so that they don't talk to me about it, ever.

let rec map f = function
| Leaf -> Leaf
| Branch (a, x, b) ->
let fa = map f a in
let fx = f x in
let fb = map f b in
Branch(fa, fx, fb)

One unusual situation where "let..and" is useful is when producing
code mechanically, for example when writing a Camlp4 extension.
Imagine I wanted to write a code-transforming function that would
transform NORM2(foo,bar) into `foo * foo + bar * bar`. To avoid effect
duplication, I actually want to produce `let x = <foo> and y = <bar>
in x * x + y * y`. By using `let x = <foo> in let y = <bar> in`, I
would expose myself to variable capture problems; I can have hygiene
with "let..and" without using gensyms -- the idea is just to
immediately bind all user-produced pieces of code at the beginning of
my expansion, under no additional scope; this can be done even when I
want to delay side-effects, by writing `let x () = <foo> and ...`

On Wed, Feb 15, 2012 at 4:18 PM, Lukasz Stafiniak <lukstafi@...> wrote:
> On Wed, Feb 15, 2012 at 4:10 PM, Boris Hollas
> <hollas@...-dresden.de> wrote:
>> Hello,
>>
>> I often see code such as
>>
>>    let typ = unrollType v.vtype in
>>    let loc = v.vdecl in
>>
>> Would it be better to write "and" for the second binding?
>
> I second the question. The rule of parsimony says that we should use
> as many "and"s as logically possible so that the dependencies between
> data are evident. But I almost never use "and" (outside of mutual
> recursion) in my code... Probably to make the code more homogeneous,
> then it is easier "for the eye" and easier to manipulate.
>
>
> ------------------------------------
>
> Archives up to December 31, 2011 are also downloadable at http://www.connettivo.net/cntprojects/ocaml_beginners
> The archives of the very official ocaml list (the seniors' one) can be found at http://caml.inria.fr
> Attachments are banned and you're asked to be polite, avoid flames etc.Yahoo! Groups Links
>
>
>
• I use let .. and pretty often but it is when the order of evaluation is of little importance. For instance, I choose let x = a and y = b instead of let x,y =
Message 2 of 13 , Feb 15, 2012
I use let .. and pretty often but it is when the order of evaluation is of
little importance.

For instance, I choose let x = a and y = b instead of let x,y = a,b or let
x = a in let y = b.

I have the tendency to relate "let x,y = a,b" with tuples and probably that
is the reason I avoid using this and I try to use let .. in only in case of
some dependency.

Sincerely

Rajat

On Wed, Feb 15, 2012 at 9:39 PM, Gabriel Scherer
<gabriel.scherer@...>wrote:

> **
>
>
> My (admittedly unjustified) personal style is to use "let .. in",
> except for mutual recursive bindings "let rec .. and ..". I'm not fond
> of using let..and directly as it adds an uncertainty on evaluation
> effect order, and -- to me -- suggest mutual dependency rather than
> non-dependency. For short, clearly effect-free bindings, I actually
> write "let x,y = foo,bar" rather than "let x = foo and y = bar".
>
> For the evaluation-order effect, consider this `map` function on binary
> trees:
>
> let rec map f= function
> | Leaf -> Leaf
> | Branch(a, x, b) ->
> let fa = map f a and fb = map f b in
> Branch(fa, f x, fb)
>
> This definition has the downside that `f` is applied in a fairly
> unpredictable, unspecified and unsatisfying order. While I don't want
> to encourage users into using `map` with weird effectful functions
> relying on evaluation order, I found it to be less painful for both me
> and them if their evil trickeries will actually work in the way they
> expect (left to right), so that they don't talk to me about it, ever.
>
> let rec map f = function
> | Leaf -> Leaf
> | Branch (a, x, b) ->
> let fa = map f a in
> let fx = f x in
> let fb = map f b in
> Branch(fa, fx, fb)
>
> One unusual situation where "let..and" is useful is when producing
> code mechanically, for example when writing a Camlp4 extension.
> Imagine I wanted to write a code-transforming function that would
> transform NORM2(foo,bar) into `foo * foo + bar * bar`. To avoid effect
> duplication, I actually want to produce `let x = <foo> and y = <bar>
> in x * x + y * y`. By using `let x = <foo> in let y = <bar> in`, I
> would expose myself to variable capture problems; I can have hygiene
> with "let..and" without using gensyms -- the idea is just to
> immediately bind all user-produced pieces of code at the beginning of
> my expansion, under no additional scope; this can be done even when I
> want to delay side-effects, by writing `let x () = <foo> and ...`
>
>
> On Wed, Feb 15, 2012 at 4:18 PM, Lukasz Stafiniak <lukstafi@...>
> wrote:
> > On Wed, Feb 15, 2012 at 4:10 PM, Boris Hollas
> > <hollas@...-dresden.de> wrote:
> >> Hello,
> >>
> >> I often see code such as
> >>
> >> let typ = unrollType v.vtype in
> >> let loc = v.vdecl in
> >>
> >> Would it be better to write "and" for the second binding?
> >
> > I second the question. The rule of parsimony says that we should use
> > as many "and"s as logically possible so that the dependencies between
> > data are evident. But I almost never use "and" (outside of mutual
> > recursion) in my code... Probably to make the code more homogeneous,
> > then it is easier "for the eye" and easier to manipulate.
> >
> >
> > ------------------------------------
>
> >
> > Archives up to December 31, 2011 are also downloadable at
> http://www.connettivo.net/cntprojects/ocaml_beginners
> > The archives of the very official ocaml list (the seniors' one) can be
> found at http://caml.inria.fr
> > Attachments are banned and you're asked to be polite, avoid flames
> >
> >
> >
>
>
>

[Non-text portions of this message have been removed]
• Also, I find that let..and increases readability and helps me identify relations (or absence of it) easily. And, aligning them like this :- let x = a and y =
Message 3 of 13 , Feb 15, 2012
Also, I find that let..and increases readability and helps me identify
relations (or absence of it) easily.

And, aligning them like this :-

let x = a
and y = b

also helps me maintain the indentation (again increases readability).

On Thu, Feb 16, 2012 at 12:48 AM, Rajat Khanduja
<rajatkhanduja13@...>wrote:

> I use let .. and pretty often but it is when the order of evaluation is of
> little importance.
>
> For instance, I choose let x = a and y = b instead of let x,y = a,b or
> let x = a in let y = b.
>
> I have the tendency to relate "let x,y = a,b" with tuples and probably
> that is the reason I avoid using this and I try to use let .. in only in
> case of some dependency.
>
> Sincerely
>
> Rajat
>
>
> On Wed, Feb 15, 2012 at 9:39 PM, Gabriel Scherer <
> gabriel.scherer@...> wrote:
>
>> **
>>
>>
>> My (admittedly unjustified) personal style is to use "let .. in",
>> except for mutual recursive bindings "let rec .. and ..". I'm not fond
>> of using let..and directly as it adds an uncertainty on evaluation
>> effect order, and -- to me -- suggest mutual dependency rather than
>> non-dependency. For short, clearly effect-free bindings, I actually
>> write "let x,y = foo,bar" rather than "let x = foo and y = bar".
>>
>> For the evaluation-order effect, consider this `map` function on binary
>> trees:
>>
>> let rec map f= function
>> | Leaf -> Leaf
>> | Branch(a, x, b) ->
>> let fa = map f a and fb = map f b in
>> Branch(fa, f x, fb)
>>
>> This definition has the downside that `f` is applied in a fairly
>> unpredictable, unspecified and unsatisfying order. While I don't want
>> to encourage users into using `map` with weird effectful functions
>> relying on evaluation order, I found it to be less painful for both me
>> and them if their evil trickeries will actually work in the way they
>> expect (left to right), so that they don't talk to me about it, ever.
>>
>> let rec map f = function
>> | Leaf -> Leaf
>> | Branch (a, x, b) ->
>> let fa = map f a in
>> let fx = f x in
>> let fb = map f b in
>> Branch(fa, fx, fb)
>>
>> One unusual situation where "let..and" is useful is when producing
>> code mechanically, for example when writing a Camlp4 extension.
>> Imagine I wanted to write a code-transforming function that would
>> transform NORM2(foo,bar) into `foo * foo + bar * bar`. To avoid effect
>> duplication, I actually want to produce `let x = <foo> and y = <bar>
>> in x * x + y * y`. By using `let x = <foo> in let y = <bar> in`, I
>> would expose myself to variable capture problems; I can have hygiene
>> with "let..and" without using gensyms -- the idea is just to
>> immediately bind all user-produced pieces of code at the beginning of
>> my expansion, under no additional scope; this can be done even when I
>> want to delay side-effects, by writing `let x () = <foo> and ...`
>>
>>
>> On Wed, Feb 15, 2012 at 4:18 PM, Lukasz Stafiniak <lukstafi@...>
>> wrote:
>> > On Wed, Feb 15, 2012 at 4:10 PM, Boris Hollas
>> > <hollas@...-dresden.de> wrote:
>> >> Hello,
>> >>
>> >> I often see code such as
>> >>
>> >> let typ = unrollType v.vtype in
>> >> let loc = v.vdecl in
>> >>
>> >> Would it be better to write "and" for the second binding?
>> >
>> > I second the question. The rule of parsimony says that we should use
>> > as many "and"s as logically possible so that the dependencies between
>> > data are evident. But I almost never use "and" (outside of mutual
>> > recursion) in my code... Probably to make the code more homogeneous,
>> > then it is easier "for the eye" and easier to manipulate.
>> >
>> >
>> > ------------------------------------
>>
>> >
>> > Archives up to December 31, 2011 are also downloadable at
>> http://www.connettivo.net/cntprojects/ocaml_beginners
>> > The archives of the very official ocaml list (the seniors' one) can be
>> found at http://caml.inria.fr
>> > Attachments are banned and you're asked to be polite, avoid flames
>> >
>> >
>> >
>>
>>
>>
>
>

[Non-text portions of this message have been removed]
• ... Most experienced OCamlers seem to prefer let...in for the default form. I don t think let/in looks any better than and , and OCaml is a functional
Message 4 of 13 , Feb 15, 2012
>> let typ = unrollType v.vtype in
>> let loc = v.vdecl in
>> Would it be better to write "and" for the second binding?
>
> I second the question.... Probably to make the code more homogeneous,
> then it is easier "for the eye" and easier to manipulate.

Most experienced OCamlers seem to prefer "let...in" for the default form. I
don't think let/in looks any better than "and", and OCaml is a functional
language, so I wouldn't worry about order of evaluation too much. The main
binding line has the same form as the first one, so you can swap them
arbitrarily without having to change the keywords.

[Non-text portions of this message have been removed]
• ... [...] The and allows mutual recursive functions. So, when using and this could be a hint to what the programmer has in mind, when using these things...
Message 5 of 13 , Feb 15, 2012
On Thu, Feb 16, 2012 at 12:50:40AM +0530, Rajat Khanduja wrote:
> Also, I find that let..and increases readability and helps me identify
> relations (or absence of it) easily.
[...]

The "and" allows mutual recursive functions.

So, when using "and" this could be a hint to what the programmer has in mind,
when using these things... at least when defining functions.

So I'm not clear if using "and" in general would make that distinction less
obvious, even both works.

If the "and" is always used, it would not give the hint to mutual recursive functions.
One would have a deeper look at the code then, assuring that there are not
mutual recursive functions used...
...when using let .. in let ... in ...
would make it obvious that there will not be mutaual recursive functions.
This might make reading the code more easy.

Also I'm not sure if there are performance issues related to the both
styles.

Ciao,
Oliver
• ... let ... in definitely restricts the order of the evaluation of the code. I m not sure if this necessarily is always the case when using and ; in principal
Message 6 of 13 , Feb 15, 2012
On Wed, Feb 15, 2012 at 03:16:32PM -0800, Dan Bensen wrote:
> >> let typ = unrollType v.vtype in
> >> let loc = v.vdecl in
> >> Would it be better to write "and" for the second binding?
> >
> > I second the question.... Probably to make the code more homogeneous,
> > then it is easier "for the eye" and easier to manipulate.
>
> Most experienced OCamlers seem to prefer "let...in" for the default form. I
> don't think let/in looks any better than "and", and OCaml is a functional
> language, so I wouldn't worry about order of evaluation too much. The main
> binding line has the same form as the first one, so you can swap them
> arbitrarily without having to change the keywords.
>
> [Non-text portions of this message have been removed]
>

let ... in

definitely restricts the order of the evaluation of the code.

I'm not sure if this necessarily is always the case when using "and";
in principal it could be valid, to evaluate the later defined items
before the former ones, because the "and" allows both definitions
be independent of each other.

Ciao,
Oliver
• ... Evaluation order is unspecified in let/and bindings. I was just saying the OCaml culture encourages programmers to ignore evaluation order whenever they
Message 7 of 13 , Feb 15, 2012
> > OCaml is a functional language,
> > so I wouldn't worry about order of evaluation
>
> let ... in definitely restricts the order of the evaluation
> I'm not sure if this necessarily is always the case when using "and"

Evaluation order is "unspecified" in let/and bindings. I was just saying the OCaml culture encourages programmers to ignore evaluation order whenever they can.
• ... But this is what you told the compiler here: I don t mind how the tree is traversed, the end result is the same. If you want to enforce a dfs then
Message 8 of 13 , Feb 16, 2012
On Wed, 2012-02-15 at 17:09 +0100, Gabriel Scherer wrote:

> let rec map f= function
> | Leaf -> Leaf
> | Branch(a, x, b) ->
> let fa = map f a and fb = map f b in
> Branch(fa, f x, fb)
>
> This definition has the downside that `f` is applied in a fairly
> unpredictable, unspecified and unsatisfying order. While I don't want

But this is what you told the compiler here: I don't mind how the tree
is traversed, the end result is the same. If you want to enforce a dfs
then evaluation order matters.

On the other hand, does

> let fa = map f a in
> let fx = f x in
> let fb = map f b in
> Branch(fa, fx, fb)

guarantee that fa is evaluated before fb? The compiler might detect that
fa is not part of let fb = map f b, and decide that both expressions can
be evaluated independently. So perhaps the sequencing operator ";"
should be used?
• ... you d have to look for a let rec at the beginning.
Message 9 of 13 , Feb 16, 2012
On Thu, 2012-02-16 at 01:15 +0100, oliver wrote:
> If the "and" is always used, it would not give the hint to mutual
> recursive functions.
> One would have a deeper look at the code then, assuring that there are
> not
> mutual recursive functions used...

you'd have to look for a "let rec" at the beginning.
• ... Yes, fa, fx, and fb will always be evaluated in that order. I would call the function itermap to emphasize the ordering. ... No, bindings before in are
Message 10 of 13 , Feb 16, 2012
> does
> > let fa = map f a in
> > let fx = f x in
> > let fb = map f b in
> > Branch(fa, fx, fb)
> guarantee that fa is evaluated before fb?

Yes, fa, fx, and fb will always be evaluated in that order.
I would call the function "itermap" to emphasize the ordering.

> The compiler might detect that fa is not part of let fb = map f b,
> and decide that both expressions can be evaluated independently.

No, bindings before "in" are always evaluated before the expression that
follows.

[Non-text portions of this message have been removed]
Your message has been successfully submitted and would be delivered to recipients shortly.