1

I wonder where this error is coming from. Here is the code, and below the TP, which uses fsahrpx DSL

Update: I found a 'solution', which is to do the cast outside and construct one getter per cast. If anyone knows why this happens, or has better solution, I'd be glad to know. (limited quotation pattern in the ProvidedTypes-0.2.fs ?)

edit : my desperate failed attempts are not so interesting. the two interesting ones are Test93 for instance, or Test92. why would they be failing ?

update added the most litigious cases 90,91,92,93

module Module =
   open System.Reflection
   open Samples.FSharp.ProvidedTypes
   open FSharpx.TypeProviders.DSL
   open Microsoft.FSharp.Core.CompilerServices

   type ReflectiveBuilder = static member Cast<'a> (args:obj) = args :?> 'a
      static member BuildTypedCast lType (args: obj) = 
            typeof<ReflectiveBuilder>
               .GetMethod("Cast")
               .MakeGenericMethod([|lType|])
               .Invoke(null, [|args|])

   let bbgReference ns =
       erasedType<obj> (Assembly.GetExecutingAssembly()) ns "Reference"
       |> staticParameter "file"
          (fun typeName (parameterValues:string) ->
               let otwo = 2.0 :> obj
               let dtwo = 2.0 
               let dotwo = otwo :?> float

               let dcast = ReflectiveBuilder.BuildTypedCast typeof<float>

               let getter = match otwo with
                              | :? double as d -> (fun args -> <@@ d @@>)
                              | :? string as d -> (fun args -> <@@ d @@>)

               erasedType<string> (Assembly.GetExecutingAssembly()) ns typeName
           |+!> (   provideProperty 
                       "test90"                             //KO
                       (typeof<obj>)                   
                       (fun args -> <@@  otwo  @@>)     
                 )
           |+!> (   provideProperty 
                       "test91"                             //KO
                       (otwo.GetType())                  
                       (fun args -> <@@  otwo  @@>)     
                 )
           |+!> (   provideProperty 
                       "test92"                             //KO
                       (otwo.GetType())                  
                       (fun args -> <@@  otwo  @@>)     
                 )
           |+!> (   provideProperty 
                       "test93"                              //NO
                       typeof<float>                   
                       (fun args -> <@@  otwo :?> float  @@>)     
                 )

               |+!> (   provideProperty 
                           "test"                             //OK
                           typeof<float>                   
                           (fun args -> <@@  dtwo  @@>)      
                     )
               |+!> (   provideProperty 
                           "test2"                              //NO
                           typeof<float>                   
                           (fun args -> <@@  dtwo :> obj @@>)     
                     )
               |+!> (   provideProperty 
                           "test3"                              //NO
                           typeof<float>                   
                           (fun args -> <@@  otwo  @@>)     
                     )
               |+!> (   provideProperty 
                           "test4"                              //NO
                           typeof<float>                   
                           (fun args -> <@@  otwo :?> float  @@>)     
                     )
               |+!> (   provideProperty 
                           "test5"                              //OK
                           typeof<float>                   
                           (fun args -> <@@  dotwo  @@>)     
                     )
               |+!> (   provideProperty 
                           "test6"                              //OK
                           typeof<float>                   
                           (fun args -> <@@  dotwo :> obj  @@>)     
                     )
               |+!> (   provideProperty 
                           "test7"                              //NO
                           typeof<float>                   
                           (fun args -> <@@  dcast otwo  @@>)     
                     )
               |+!> (   provideProperty 
                           "test8"                              //OK
                           typeof<float>                   
                           getter    
                     )
               |+!> (provideConstructor
                        []
                        (fun _ -> <@@ "I will be the internal representation" @@>)))


   [<TypeProvider>]
   type public CustomTypeProvider(cfg:TypeProviderConfig) as this =
      inherit TypeProviderForNamespaces()

      do this.AddNamespace("TEST", [bbgReference "TEST"])

   [<TypeProviderAssembly>]
   do()

the tests

module Program =
   open System

   type t = TEST.Reference<"">
   let price = t().Test90
   let price = t().Test91
   let price = t().Test92
   let price = t().Test93
   let price = t().Test    //OK
   let price = t().Test2   //OK
   let price = t().Test3   //NO OK
   let price = t().Test4   //NO OK
   let price = t().Test5   //OK
   let price = t().Test6   //OK
   let price = t().Test7   //NO OK
   let price = t().Test8   //OK
nicolas
  • 9,549
  • 3
  • 39
  • 83
  • if you're unaware, Tomas Petricek was one of the developers on the team that created F#. You're extremely unlikely to get a much more authoritative answer unless Brian McNamara or Don Syme weighs in on the question. – Onorio Catenacci Apr 28 '12 at 18:47
  • Hi @OnorioCatenacci, I highly value Tomas input, and am aware of his skills on those new typing machines ;) I think here it is more a question of knowing the (really) low levels of the Type Provider API which can be rough at edge. (cf my other question about user types in quotations....http://stackoverflow.com/questions/10357273/type-provider-calling-another-dll-in-f ) – nicolas Apr 29 '12 at 10:59
  • @OnorioCatenacci I wouldn't say I was one of the developers who created F# - I was there as an intern and I still do a couple of things closely with the F# team, but I'm sure there is quite a few people who spent more time studying & implementing type providers! – Tomas Petricek Apr 30 '12 at 02:16
  • @TomasPetricek all modesty aside, I doubt that Nicolas is going to get a much better informed answer than yours which is what I was sort of trying to point out to him. – Onorio Catenacci Apr 30 '12 at 16:34

2 Answers2

3

The expressions that can appear in quoted code for properties and methods for F# type providers are quite limited - I faced the same problem when writing a type provider. I don't think there is a precise specification at the moment, so the only way to find out is to look at the source code or experiment with it.

The reason is that compiling F# quotations to IL wasn't already fully implemented anywhere and so the code generator for type providers probably just implements the basic functionality that is sufficient to make it work.

When writing providers, I generally follow a pattern where all the "runtime" code is placed in a module and the quoted code passed to methods or properties just calls this runtime. This works, because the quotation is just a method call. Something like:

module CultureRuntime =
  let getCulture (name:string) = 
    // The runtime can contain arbitrary complex F# code
    CultureInfo.GetCultureInfo(name)

When adding properites to a provider, the quotation just calls CultureRuntime.getCulture:

for culture in CultureInfo.GetCultures(CultureTypes.AllCultures) do
  let id = culture.Name
  ProvidedProperty
    ( culture.DisplayName, typeof<CultureInfo>, IsStatic = true,
      GetterCode = fun args -> <@@ CultureRuntime.getCulture id @@>)
  |> sampleTy.AddMember

EDIT: I'm not too familiar with how the code generation for type providers works internally, but the cases that you find surprising almost always work with <@ otwo @> or similar, where otwo is something of type System.Object.

When the type provider generates code from the quotation, it needs to generate IL code for the expression otwo. However, this does not make sense in general, because if otwo is of type System.Object, then you cannot generate IL that re-creates the object (or serialize the object in some other way).

For this reason, the F# type provider mechanism (probably) only allows primitive values that can be easily translated to IL (such as values of type float as in your <@ dtwo @> example).

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • well noted. thank you very much for the practical advice. the code looks yound indeed. like 2 month ago it was not even quotations, but Linq behind the scene.. Do you think eventually they'll cover the whole f# in quotations ? (Sounds like something to do but is it really the case) – nicolas Apr 15 '12 at 14:25
  • There must be something else, because this is not the cause. you will see in my exemple I only use very simple expression, like method calls. – nicolas Apr 15 '12 at 16:52
  • it seems that if the Compile time result of the expression is not the same as the compile time type if a declared property, it generates an error, and cast in quotation yields the same for whatever reason. – nicolas Apr 15 '12 at 17:09
  • I think it is a bug. I dont have access to all the call but : TEST91 split the same Expression as a result of GetInvokerExpression r = {Value (2.0)} . And the method have the same description. I dont see how in hell it generates a bug ! – nicolas Apr 15 '12 at 18:09
  • I emailed the fine people in charge of the VS Beta. hopefully we'll have this fixed... – nicolas Apr 16 '12 at 19:30
  • @nicolas I added some more information about the `<@ otwo @>` cases. I hope it clarifies the situation a bit. – Tomas Petricek Apr 30 '12 at 02:14
2

We are planning to publish updates/fixes to ProvidedTypes API on samples codeplex site in coming weeks. This issue will be addressed as well.

desco
  • 16,642
  • 1
  • 45
  • 56
  • The provided types is a major functionality. Glad to see that rough edges are worked out. Communication always greatly appreciated. – nicolas May 02 '12 at 22:25
  • You may want to try new version we've recently published on the CodePlex – desco May 19 '12 at 08:52