Skip to content

Reflection for classes #2027

Open
Open

Description

@Shmew

I've been working on bindings for fast-check which are mostly complete.

The library has the ability to do model-based testing, which I have implemented:

image

The thing I'd like to do is automatically generate a complete Arbitrary<'Msg> if it's possible as I believe it would make writing these cases even easier.

I have reflection working for almost all types, but the thing giving me trouble is getting class constructors.

Is this something that can currently be resolved with Fable? If not, is adding the support for these feasible?

Activity

  1. changed the title [-]Reflection for classes and inner values of generic types[/-] [+]Reflection for classes[/+] on Apr 16, 2020
  2. Shmew commented on Jun 3, 2020

    @Shmew
    ContributorAuthor

    @alfonsogarciacaro think you could give me guidance on where to start with implementing this? I'd be willing to try a PR if I had a better idea of where to start.

  3. alfonsogarciacaro commented on Jun 4, 2020

    @alfonsogarciacaro
    Member

    Well, actually I think @krauthaufen has already done that in #1839 which, besides adding support for quotations, increases the support for reflection. I've been very busy for the last months so I couldn't check the PR properly but time allowing I'll try to start publishing alpha/beta versions of Fable 3 based on the PR soon.

    In any case, there are instructions in the PR description about how to test it right now. The fable-compiler-quotations package is a bit old, but I'll merge the branch with master and publish a new version.

  4. alfonsogarciacaro commented on Jun 4, 2020

    @alfonsogarciacaro
    Member

    Having trouble with merging master into quotations but forgot to mention System.Activator is supported in the latest version of Fable, so you can do something like this (inlining is important to know the type at compile time):

    type A(i1: int, i2: int) =
        member x.Value2 = i2 + i2
    
    let inline activate<'T> (args: obj[]) =
        System.Activator.CreateInstance(typeof<'T>, args) :?> 'T
    
    let test() =
        let a = activate<A> [|4; 5|]
        a.Value2 |> printfn "%i"
    
    test()
  5. alfonsogarciacaro commented on Jun 4, 2020

    @alfonsogarciacaro
    Member

    You can check the Reflection tests to see what's currently supported. FSharpValue.MakeRecord/MakeUnion are supported too.

  6. Shmew commented on Jun 4, 2020

    @Shmew
    ContributorAuthor

    I've explored quite a bit with what we can currently reflect when making fast-check bindings for fable.

    System.Activator is supported in the latest version of Fable

    Yeah, that's what got me thinking about this issue again actually! The issue I'm having that prevents just using that is I need to be able to tell given a System.Type if it is a class. If there's something else available currently that would solve this that would be great too!

  7. alfonsogarciacaro commented on Jun 4, 2020

    @alfonsogarciacaro
    Member

    A class in what sense? Something that's not a record, a union, a tuple, an array or an enum? In that case, maybe you can just write a helper to discard the rest of the options.

  8. Shmew commented on Jun 4, 2020

    @Shmew
    ContributorAuthor

    So my use-case is I want to be able to automatically generate an arbitrary of any type using default primitive arbitraries (if necessary).

    So for example if they have something like this:

    type MyClass (someNum: int) =
        let mutable someInnerState = someNum
        member _.AddOne () = someInnerState <- someInnerState + 1

    Which I would receive a System.Type of MyClass. Then I would be able to create an arbitrary for someNum and construct the class by mapping that arbitrary into the constructor.

  9. alfonsogarciacaro commented on Jun 5, 2020

    @alfonsogarciacaro
    Member

    Hmm, this can be done with Activator, but the problem is we cannot know the types of the constructor arguments for a class right now (this can be done with records and unions though), but it would be very interesting for your use case, I'll see what I can do.

    I was a bit reluctant to include information for all the class members because it could increase the bundle size, but maybe we could generate an independent getMembers method that gets removed by tree shaking if not being called. The only caveat would be that you need to know the type at compile time to access the members as in:

    let inline getMembersOf<'T>() =
        typeof<'T>.GetMembers()
    
    getMembersOf<MyClass>()
  10. Shmew commented on Jun 5, 2020

    @Shmew
    ContributorAuthor

    Yeah all the types would be known at compile time, that would be great!

  11. alfonsogarciacaro commented on Nov 1, 2020

    @alfonsogarciacaro
    Member

    Related #2085

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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