fsharp icon indicating copy to clipboard operation
fsharp copied to clipboard

Cannot use `base` as identifier in a class, even double-backticked

Open Tarmil opened this issue 2 years ago • 0 comments

There seems to be some inconsistency in whether base is treated as a keyword or as an identifier.

Repro steps

On one hand, this suggests that it is a keyword:

let base = 1
// Error: Unexpected keyword 'base' in binding

and indeed, it can be double-backticked:

let ``base`` = 1
// val ``base`` : int = 1

However, when in the context of a class that inherits from another class, it behaves more like an identifier: it always refers to the base class, even if backticked:

let ``base`` = 1

type BaseClass() =
    member _.BaseMethod() = ()

type SomeClass() =
    inherit BaseClass()

    member _.Works() = base.BaseMethod() // Calls the base class, as expected

    member _.Unexpected() : int = ``base`` // Error: This expression was expected to have type 'int' but here has type 'BaseClass'

Expected behavior

``base`` refers to the variable defined above.

Actual behavior

``base`` refers to the base class, just like base.

Known workarounds

If the identifier ``base`` is defined in another module that is opened, then it can be referred to using a qualified name. But if it's defined directly in the parent module, then I think the only workaround is to rename it.

Related information

F# 8 / .NET SDK 8.0.100.

Context

I am running into this issue in the context of Bolero, where ``base`` is an HTML element. Because of this issue, it cannot be used directly inside a component (ie. a class that inherits from Bolero.Component). Instead, you have to use Bolero.Html.``base``, or define your HTML in a function outside the component and call that function from the component.

Annoyingly, it fails with a very confusing error message, because we're trying to use a Component as a CE builder:

open Bolero.Html
open Bolero.Server.Html

type HelloWorldPage() =
    inherit Bolero.Component()

    override _.Render() =
        doctypeHtml {
            head {
                ``base`` { attr.href "/" } // Error: This control construct may only be used if the computation expression builder defines a 'Zero' method
            }
            body { "Hello, world!" }
        }

Tarmil avatar Jan 03 '24 11:01 Tarmil