Search code examples
f#shadowing

How to shadow a record in F# Program.fs?


I'm following the F# book Get Programming with F# and got to the part about shadowing. The simplest example they provide doesn't seem to be possible, so I'm wondering if either this syntax was removed or changed for F# 6 shadowing? I haven't been able to find anything stating that or how to do what the book offers as shadowing a record.

type Address =
    { Street: string
      Town: string
      City: string }

let home = { Street = "123 Main Street"; Town = "The Town"; City = "The City" }
let home = { home with City = "Second City" }
let home = { home with City = "Third City" }

When trying to build get an error stating: Duplicate definition of value 'home'


Edit

So after searching for answers without success as to why this doesn't work I tried putting the above into a function like so:

let testFunction = 
    let home = { Street = "123 Main Street"; Town = "The Town"; City = "The City" }
    let home = { home with City = "Second City" }
    let home = { home with City = "Third City" }
    0

and it worked just fine. So my question now is why does shadowing work within a function but not outside? Is there a conflict with scoping on a module level that doesn't happen within a function's scope?


Solution

  • To add some more detail to the existing answers, there are four different cases.

    Local definitions. If you are inside a function body, you can use shadowing and this is quite useful when doing a computation in multiple steps:

    let adjust index = 
      let index = max 0 index
      let index = min 100 index
      index
    

    Local definitions inside class. You are similarly allowed to shadow local definitions inside a class:

    type A() = 
      let foo = 1
      let foo = 2
      member x.Foo = foo
    

    Top-level in a script file. If you are at the top level in a script file (something.fsx) then you are allowed shadowing. The idea with script files is that they would be run manually, so it is useful to have multiple different versions - you just run the one you want by hand:

    let test = calculation1 ()
    let test = caluclation2 ()
    

    Top-level in a module (source file). The only case where shadowing does not work is when you are in a module (or .fs file which becomes a module implicitly). In a module, definitions are public and they are compiled as static members of a class, so there is also a technical limitation (you cannot have multiple class members of the same name).

    module Constants = 
      let answer = 1
      let answer = 42 // error FS0037: Duplicate definition of value