Loading ...
Sorry, an error occurred while loading the content.

Re: Coding style: let vs and

Expand Messages
  • Richard Stoerzer
    On Wed, 15 Feb 2012 16:10:14 +0100 ... I prefer and . This way it s apparent for the reader, that a) The second binding don t depend on the first one b) the
    Message 1 of 13 , Feb 15, 2012
    • 0 Attachment
      On Wed, 15 Feb 2012 16:10:14 +0100
      Boris Hollas <hollas@...-dresden.de> wrote:
      > 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 prefer "and". This way it's apparent for the reader, that
      a) The second binding don't depend on the first one
      b) the order of evaluation doesn't matter

      Only if a) or b) doesn't apply, I use two sequential let bindings.
    • Gabriel Scherer
      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 2 of 13 , Feb 15, 2012
      • 0 Attachment
        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 ...`
        instead.

        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
        >
        >
        >
      • Rajat Khanduja
        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 3 of 13 , Feb 15, 2012
        • 0 Attachment
          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 ...`
          > instead.
          >
          >
          > 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
          > >
          > >
          > >
          >
          >
          >


          [Non-text portions of this message have been removed]
        • Rajat Khanduja
          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 4 of 13 , Feb 15, 2012
          • 0 Attachment
            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 ...`
            >> instead.
            >>
            >>
            >> 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
            >> >
            >> >
            >> >
            >>
            >>
            >>
            >
            >


            [Non-text portions of this message have been removed]
          • Dan Bensen
            ... 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 5 of 13 , Feb 15, 2012
            • 0 Attachment
              >> 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
              advantage of let/in seems to be your last point about editing the code: Every
              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]
            • oliver
              ... [...] 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 6 of 13 , Feb 15, 2012
              • 0 Attachment
                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
              • 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 7 of 13 , Feb 15, 2012
                • 0 Attachment
                  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
                  > advantage of let/in seems to be your last point about editing the code: Every
                  > 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
                • danbensen@att.net
                  ... Evaluation order is unspecified in let/and bindings. I was just saying the OCaml culture encourages programmers to ignore evaluation order whenever they
                  Message 8 of 13 , Feb 15, 2012
                  • 0 Attachment
                    > > 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.
                  • Boris Hollas
                    ... 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 9 of 13 , Feb 16, 2012
                    • 0 Attachment
                      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?
                    • Boris Hollas
                      ... you d have to look for a let rec at the beginning.
                      Message 10 of 13 , Feb 16, 2012
                      • 0 Attachment
                        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.
                      • Dan Bensen
                        ... 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 11 of 13 , Feb 16, 2012
                        • 0 Attachment
                          > 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.