question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Stubborn warning FS0193 on valid code

See original GitHub issue

The following code typechecks and runs without issue, but generates a spurious warning about a missing type parameter constraint, and there seems to be no obvious solution to satisfy the compiler. This is happening on Visual F# 3.1.2.

#!/usr/bin/env fsharpi

open System

type CShow = class
  static member inline show (x : int) = sprintf "%d" x
  static member inline show (x : string) = sprintf "\"%s\"" x
end

type Instance<'a, 'b, 'c when
             (^a or ^b) : (static member show : ^b -> ^c)> = class
  static member inline instance (b : ^b) =
    ((^a or ^b) : (static member show : ^b -> ^c) b)
end

type IShow = interface
  abstract show : unit -> string
end

let inline Show arg = {
  new IShow with
  member __.show () = Instance<CShow, _, string>.instance arg }

let inline cout (x : string) = Console.WriteLine x
let inline show (x : #IShow) = x.show ()

let _ =
  [Show 1; Show "arsdf"]
  |> List.iter (show >> cout)

The warning is: Blarg.fsx(13,5): warning FS0193: A type parameter is missing a constraint 'when ( ^a or ^b) : (static member show : ^b -> 'c)' (the line with the static member invocation).

Issue Analytics

  • State:open
  • Created 8 years ago
  • Comments:13 (12 by maintainers)

github_iconTop GitHub Comments

1reaction
smoothdevelopercommented, Nov 7, 2021

@dsyme, seeing the other “generic type pretty printing” related issues getting coallesced with this older one (makes sense), and on the topic of the pretty printing approach becoming easier to use to contributors, I was wondering if by gleaning more intuition about how this code evolved and ideally would be supposed to work, you may be in a place to improve that infrastructure with stronger invariants / making it easier for contributors to leverage?

I remember the pretty printing with those concerns was a bit of a sticking point I had to grok based on your input, when doing the overload resolution failure error message work, I didn’t feel super confident using the right APIs and in my refactorings to enable what I ended up using in the implementation.

It would be great if someone had a clear idea on how we could architecturally solve this (consuming the code being correct 99% of time just by construction, and refactoring/extending the infrastructure feeling less “what am I going to break” inducing, at least for casual contributors).

It could be there is just a missing call to “convert unnamed identifier to generic identifier for pretty printing” in many/some places, but just fixing it with current infrastructure may not address the potential for the issue to show when adding code, if there is already some knowledge about feasibility of addressing the later, it peaks my curiosity that some of this knowledge would write itself in this issue until a plan is put by the community to address it in the code.

0reactions
nicklecomptecommented, Aug 8, 2021

I don’t want to distract anyone on an at-worst irritating bug, but I have a funny reproduction in F# 5.0 (in .NET Standard 2.0) that might shed some light on this strange behavior.

The following simple example raises a warning like the ones above:

type TwoDPoint< ^T when ^T : (static member (+) : ^T * ^T -> ^T ) > = 
    {xpt: ^T; ypt: ^T}
with
    static member inline (+) (a : TwoDPoint< ^T>, b : TwoDPoint< ^T>) : TwoDPoint< ^T>  = 
        {xpt = a.xpt + b.xpt; 
         ypt = a.ypt + b.ypt}

The specific warning: A type parameter is missing a constraint 'when ( ^T or ^?769536) : (static member ( + ) : ^T * ^?769536 -> ^T)' (the random number usually indicates to me that the compiler is being fussy for some reason)

However, this works without any warnings:

type TwoDPoint< ^T when ^T : (static member (+) : ^T * ^T -> ^T ) > = 
        {xpt: ^T; ypt: ^T}
with
    static member inline (+) (a,b) : TwoDPoint< ^T>  = 
        {xpt = a.xpt + b.xpt; 
         ypt = a.ypt + b.ypt}

IntelliSense shows that F# is interpolating the types correctly. So for some reason F# doesn’t like the type annotations in this specific case. Funnily, I have this hideous type defined later which works flawlessly:

type ColumnVector< ^T when 
       ^T : (static member (+) :  ^T * ^T -> ^T ) and 
       ^T : (static member (-) : ^T * ^T -> ^T ) and 
       ^T : (static member (*) : ^T * ^T -> ^T) and 
       ^T : (static member (/) : ^T * ^T -> ^T) and
       ^T : (static member Zero : ^T) and 
       ^T : (static member Sqrt : ^T -> ^T) and
       ^T : struct and
       ^T : equality> = 
   static member inline (+) 
       ((vec1: ColumnVector< ^T >), (vec2: ColumnVector< ^T> )) : ColumnVector< ^T> = // no problem
   static member inline (*) ((s: ^T),(v: ColumnVector< ^T>)) : ColumnVector< ^T> = // no problem
   // and so on

So this style of chaining together static member constraints can work really well at creating robust polymorphic code. It’s just a head scratcher when the compiler complains about it in seemingly arbitrary places.

Read more comments on GitHub >

github_iconTop Results From Across the Web

F# 4.5.0.0: error FS0193: This expression is a function ...
I'm adapting a class from C# to F#, in the code I have a method that throws an exception and this method needs...
Read more >
Untitled
02336 code, Belas donas flores, Ou spring game 2014 tv channel, Ct70 lifan 140, ... Hillyard spokane boundaries, Gironda chest press, True crime...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found