In the last tutorial, we built a simple type named
Hello which had some static members. In this tutorial, we’ll expand our
Hello type to include a constructor, an instance property, and an instance method. Adding these will allow us to create instances of
Hello using the
We’ll also make
Hello store some data, that means our type providers will be one step closer to awesome. Also, one step closer to being an effective means of interacting with structured data sources.
The full code for what we make in this part will be at the end of this post. ### Quick Overview Here’s the order of what we’ll be doing in Part 3 of this tutorial series
- Add a constructor to
Hellostore a single integer value.
- Add a parameterized construtor to
Hello. This will let us set the value for
- Add an instance property which returns the integer set by the constructor.
- Add an instance method which doubles the integer set by the constructor.
Along the way, we’ll see the backing
obj type for the first time. This is where the idea of “Erased Types” I mentioned in Part 1 becomes important. Remember, as far as the runtime is concerned, our generated types are just instances of
obj (all the methods, properties, and names we generate with our Type Providers are illusions to help developers write better code).
Constructors - Tonka Tough
In order to make our type instantiable, we have to have a constructor. It could be a default constructor or one with parameters, it doesn’t matter, but at least one must exist.
The ProvidedTypes module includes a nice type specifically for handling constructors:
ProvidedConstructor. Not a very surprising name, if you’ve been paying attention :).
We’re going to add a default constructor to
Hello (meaning it takes no parameters) which sets the value of our
Hello instance to 0.
1 2 3 4 5 6 7 8 9 10 11 12 13
There really is not much to talk about here, it’s very simple. Except, I want to call out the
InvokeCode, because this is the first time we interact with the backing
As I mentioned before, our
Hello type basically sits on top of an instance of a formless
InvokeCode defines a function which gets executed when the construtor for
Hello is called. The value returned by our function is assigned to our underlying
obj. In our case, our
InvokeCode function just returns
0, because this will get assigned to a
obj' type we cast it to obj
using 0 :> obj`.
Constructors with Parameters - Construx
Now, being able to instantiate
Hello is nice, but pretty pointless if we can’t give it any values other than 0. So here’s how we create a constructor which takes a parameter.
1 2 3 4 5 6 7 8
ProvidedParameter("v", typeof<int>)]- This is how we define a parameter for a function or constructor. The
"v"is the name of the parameter. Followed by the type of our parameter.
<@@ ( %%(args.) : int) :> obj @@>- This extracts the value of our first parameter (which is
vfor those keeping score), casts it to an integer, and then boxes it to
%%is a Code Quotation operator used for “splicing”; this is used to “splice” the
argsvalue into a Code Quotation.
Try loading our new type provider into F# interactive and executing
let x = new Tutorial.Hello(1)!
Instance Property - 9/10 of the Law
Now we can instantiate our
Hello type. We have some data behind our type. Let’s add a way to get that data!
1 2 3 4
ProvidedProperty is very similar to the one we used for making a static property: we specify the name of the property and its type. However, the
GetterCode is important for us to review:
What’s important here is the
(%%(args.) : obj). More specifically, I want to call out the
args.: when dealing with instance methods or properties
arg. is where the value of our instance is stored. In the case of
Hello, our instance is just an integer, so we case
arg. to an integer and return that value.
Try running this in the F# Interactive console:
1 2 3
Instance Methods - Elementary
Finally, to wrap up this part of the tutorial. We will add an instance method which, when invoked, will return twice the
Value of our instance of
The code for this is eerily similar to most of the other code we’ve written for properties, methods, and constructors:
1 2 3 4 5 6 7
1 2 3
This is probably the most important part of the tutorial so far. We have actually created a Type Provider which generates a type named
Hello that can store some data (granted only a single integer :)). We also made this an instantiable type. The most important thing is that we got to see the underlying
obj upon which our generated type is built.
This underlying type is critical and we will explore it further in a later section of this tutorial.
If anything is learned from Part 3, it’s that our generated type is really just some frosting put on top of an existing type (in
Hello’s case an integer). This may seem silly right now, but keep in mind, the real purpose of a type provider is to allow us to point to a source of data and get a bunch of types which will let us work with that data source in a very F# like manner.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86