Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In quoted expressions or reflected definitions operators involved in constraints are not permitted although a named method with the same constraint is? #6344

Closed
7sharp9 opened this issue Mar 20, 2019 · 3 comments

Comments

@7sharp9
Copy link
Contributor

7sharp9 commented Mar 20, 2019

Please provide a succinct description of the issue.

Repro steps

Provide the steps required to reproduce the problem

In Falanx we consuming Fleece for record type like this, using combinators to form codecs for transforming to and from json types:

type NewSampleMessage =
    { mutable martId : int option
      mutable test_oneof : string option }
    
    static member JsonObjCodec =                
        fun m t -> {martId = m; test_oneof = t}
        <!> jopt "martId"  (fun b -> b.martId)
        <*> jopt "test_oneof" (fun a -> a.test_oneof)

With these definitions you are not allowed to add the reflected definition attribute:

    [<ReflectedDefinition>]
    static member JsonObjCodec =                
        fun m t -> {martId = m; test_oneof = t}
        <!> jopt "martId"  (fun b -> b.martId)
        <*> jopt "test_oneof" (fun a -> a.test_oneof)

Screen Shot 2019-03-20 at 13 09 53

But adding some extension methods that use exactly the same constraints works fine:

[<AutoOpen>]
module FleeceExtensions =
    open FSharpPlus
    open Fleece.Newtonsoft
    type ConcreteCodec<'S1, 'S2, 't1, 't2> with
        static member inline map  (field: ConcreteCodec<'S, 'S, 'f, 'T>) (f) =
            f <!> field
        
        static member inline apply  (currentField: ConcreteCodec<'S, 'S, 'f, 'T>) (remainderFields: ConcreteCodec<'S, 'S, 'f ->'r, 'T>) =
            remainderFields <*> currentField

type NewSampleMessage =
    { mutable martId : int option
      mutable test_oneof : string option }
    
    [<ReflectedDefinition>]
    static member JsonObjCodec =                        
        fun m t -> {martId = m; test_oneof = t}
        |> ConcreteCodec.map (jopt "martId"  (fun b -> b.martId))
        |> ConcreteCodec.apply (jopt "test_oneof" (fun a -> a.test_oneof))

The reflected definition can be easily extracted now:

Lambda (unitVar0,
        Call (None, op_PipeRight,
              [Call (None, op_PipeRight,
                     [Lambda (m, Lambda (t, NewRecord (NewSampleMessage, m, t))),
                      Application (Lambda (arg00,
                                           Lambda (arg10,
                                                   Call (None,
                                                         ConcreteCodec`4.map.Static,
                                                         [arg00, arg10]))),
                                   Call (None, jopt,
                                         [Value ("martId"),
                                          Lambda (b,
                                                  PropertyGet (Some (b), martId,
                                                               []))]))]),
               Application (Lambda (arg00,
                                    Lambda (arg10,
                                            Call (None,
                                                  ConcreteCodec`4.apply.Static,
                                                  [arg00, arg10]))),
                            Call (None, jopt,
                                  [Value ("test_oneof"),
                                   Lambda (a,
                                           PropertyGet (Some (a), test_oneof, []))]))]))

If we can quote the named versions I don't see why the operator version will not work either? Is this an artificial constraint or an edge case that has not yet been plumbed in?

Expected behavior

The expressions that can be quoted with a named function should be able to be quoted with an operator version.

Actual behavior

Only the named function version can be quoted

Known workarounds

Don't use operators, although the code in this instance is not as well defined as using the operators, the operator style combinators in fleece is easy to understand and has no parenthesis.

Related information

Provide any related information

@dsyme
Copy link
Contributor

dsyme commented Mar 20, 2019

@7sharp9 Yes, trait calls aren't represented in quotations and you'll get a compile-time error if you use one. Calling a method that happens to have a trait constraint is not a trait call.

So this is by design but is a limitation we should look at lifting.

@dsyme
Copy link
Contributor

dsyme commented Mar 20, 2019

Note that you can get around this by defining an operator in scope to mediate the trait call, e.g.

let inline (<*>) (x: ^T) (y: ^U) = ((^T or ^U) : (static member (<*>): ^T * ^U -> ^V) (x, y))

etc. etc. I think it's the absence of these operator definitions (i.e. the use of implicit operators) that's causing you problems.

@cartermp
Copy link
Contributor

Closing this out as something no longer a by-design limitation as of #6810

This currently does require the preview langversion to activate, but I would expect it to work with the feature

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants