Skip to content

Using string obj vs obj.ToString() leads to problems: the type parameter can escape its scope #7958

Closed
@abelbraaksma

Description

@abelbraaksma

I was refactoring some old code, replacing x.ToString() with string x for readability and, let's face it, best practices. But much to my surprise, this didn't work in a number of cases, though I always thought the two were interchangeable (with the exception of null, which is treated as "" for string null and as NRE for null.ToString(), hence the preference for string vs .ToString()).

It can lead to this:

image

But I don't think anything is "escaping its scope" here...

Repro steps

It is thrown by this code:

type Foo<'T> =
    | Bar of 'T
    override this.ToString() =    // FS0670
        match this with
        | Bar x -> string x

Expected behavior

It should compile. The string function is so basic to the language, it should be used whenever x.ToString() can be used.

Actual behavior

Using string can raise the following compile error:

FS0670 This code is not sufficiently generic. The type variable ^T could not be generalized because it would escape its scope.

Known workarounds

I found two workarounds:

  1. Don't use string and stick to ToString(), but that's a PITA
  2. Write your own function (inline or not) that doesn't expose this problem:
    /// Shadowing Core.string function.
    /// Uses obj.ReferenceEquals instead of isNull to prevent null-constraint
    let string x = if obj.ReferenceEquals(x, null) then "" else x.ToString()

Related information

Seen on any recent F# version. I did not (yet) test whether this is a regression.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions