F# nameof operator not a first-class function
Asked Answered
S

1

7

I'm using F# 4.7 with <LangVersion>preview</LangVersion> in my project file.

I have a type like this:

type Record = {
  Name : string
  Description : string
  FieldNotInterestedIn: int
}

I'd like to get the names of certain fields in a type-safe way, but not all of them. I know I can get all the field names using reflection.

Here's the most concise code I came up with. Can it be any more concise?

let certainFieldNames =
  let r = Unchecked.defaultof<Record>
  
  [
    nameof r.Name
    nameof r.Description
  ]
Silverman answered 20/7, 2020 at 19:6 Comment(5)
I'm not sure I get the question - are you asking whether you could do [r.Name; r.Description] |> List.map nameof ? That would not work, because nameof is a special operator rather than a normal function...Fob
I tried that first and wondered why nameof is intentionally not a first-class function.Silverman
I also want to know if I can do this without creating an instance of a value like I did using Unchecked.defaultof<Record>.Silverman
It would be nice to do something like nameof Record.Name.Silverman
@brett, you can do that, using defaultof is the preferred way, as it'll get erased. Besides, even if it didn't, that function never creates an instance of a reference type anyway.Roughhew
R
8

The special function nameof is a compile time feature, and returns the static name of the identifier. As such, it cannot be used at runtime, your runtime code will not contain any references to the function, the result is always a compile time constant.

As a consequence of this, you cannot use it with piping, or as a first class function. When you try it, you'll get the error as given.

The code you wrote is about the most concise, since you seem to want to get the name of these identifiers. There's no syntactic way to do this dynamically (other than with reflection, but that's a whole different approach).

The main reason this special function/operator was added was to help with renaming operations in code, or to safely use the name of a parameter in exceptions like ArgumentNullException.

Full details are in the RFC, in particular the section "other considerations", which details your use case: https://github.com/fsharp/fslang-design/blob/master/preview/FS-1003-nameof-operator.md

In the implementation, a long discussion was held with respect to not requiring the use of Unchecked.defaultof, but we couldn't find a good way of doing that without a significant rewrite of the parser. Note that that code doesn't add runtime overhead, it's erased.

Roughhew answered 20/7, 2020 at 21:51 Comment(1)
Discussion for relevant use case has now moved, can now be found here: github.com/fsharp/fslang-design/blob/master/FSharp-5.0/…Ytterbium

© 2022 - 2024 — McMap. All rights reserved.