10

I noticed that the following code compiles and works in VS 2013:

let f() =
    do Console.WriteLine(41)
    42

But when looking at the F# 3.0 specification I can't find any mention of do being used this way. As far as I can tell, do can have the following uses:

  • As a part of loop (e.g. while expr do expr done), that's not the case here.
  • Inside computation expressions, e.g.:

    seq {
        for i in 1..2 do
        do Console.WriteLine(i)
        yield i * 2
    }
    

    That's not the case here either, f doesn't contain any computation expressions.

    Though what confuses me here is that according to the specification, do should be followed by in. That in should be optional due to lightweight syntax, but adding it here causes a compile error (“Unexpected token 'in' or incomplete expression”).

  • Statement inside a module or class. This is also not the case here, the do is inside a function, not inside a module or a class.

I also noticed that with #light "off", the code doesn't compile (“Unexpected keyword 'do' in binding”), but I didn't find anything that would explain this in the section on lightweight syntax either.

Based on all this, I would assume that using do inside a function this way should not compile, but it does. Did I miss something in the specification? Or is this actually a bug in the compiler or in the specification?

svick
  • 236,525
  • 50
  • 385
  • 514
  • 2
    It's called a `do` binding. I couldn't find it in the spec, but it's [documented on MSDN](http://msdn.microsoft.com/en-us/library/dd393786.aspx). – Daniel Jul 16 '14 at 12:18
  • @Daniel That's the third case I mentioned, `do` inside a module. “Use a do binding when you want to execute code *independently of a function*” – svick Jul 16 '14 at 12:19
  • 1
    To finish the quote: _independently of a function *or value definition*._ The second case could be applicable within a function. – Daniel Jul 16 '14 at 12:21
  • The definition of _module-function-or-value-defn_ is possibly relevant here: `module Foo = do ()` doesn't compile either with `#light "off"`. – kaefer Jul 16 '14 at 12:21
  • _Independently of a function_ would describe top-level `do` bindings (in a module or class constructor). Other `do` bindings could appear anywhere a `unit` expression is allowed. – Daniel Jul 16 '14 at 12:26
  • @Daniel In the spec, it's in §10.2.5 for modules and §8.6.1.3 for classes. In either cases, I didn't find anything about `do` bindings in functions. – svick Jul 16 '14 at 12:27
  • @kaefer That's because you're using light syntax, `module Foo = begin do () end` does compile with `#light "off"`. – svick Jul 16 '14 at 12:29
  • Apparently it's missing from the spec. – Daniel Jul 16 '14 at 12:34
  • The spec isn't 100% comprehensive. – N_A Jul 16 '14 at 13:34

2 Answers2

7

From the documentation on MSDN:

A do binding is used to execute code without defining a function or value.

Even though the spec doesn't contain a comprehensive list of the places it is allowed, it is merely an expression asserted to be of type unit. Some examples:

if ((do ()); true) then ()
let x: unit = do ()

It is generally omitted. Each of the preceding examples are valid without do. Therefore, do serves only to assert that an expression is of type unit.

Daniel
  • 47,404
  • 11
  • 101
  • 179
  • I think the spec disallows it, since it isn't listed as one of the choices for `expr` (§6 and §A.2.3). – svick Jul 16 '14 at 15:08
  • Over the past few years I've seen many examples of `do` used in a function or method. If this behavior isn't intentional, it is de facto valid at this point. However, I think that isn't the case and the spec is incomplete on this point. – Daniel Jul 16 '14 at 15:14
0

Going through the F# 3.0 specification expression syntax has do expr as a choice of class-function-or-value-defn (types) [Ch 8, A.2.5] and module-function-or-value-defn (modules) [Ch 10, A.2.1.1].

I don't actually see in the spec where function-defn can have more than one expression, as long all but the last one evaluate to unit -- or that all but the last expression is ignored in determining the functions return value.

So, it seems this is an oversight in the documentation.

Christopher Stevenson
  • 2,843
  • 20
  • 25
  • “I don't actually see in the spec where `function-defn` can have more than one expression” That's thanks to the `expr = expr; expr` rule and the fact that lightweight syntax makes the semicolon optional. – svick Jul 17 '14 at 09:26