I am a functional-oriented developer. I have a bit of expertise in game development, especially in Unity 3D. It comes naturally that I am interested in the obvious link between the two: F#.
F# is a functional language of the ML family born in the Microsoft Research and now developed by the F# Software Foundation. Of course, F# run on the .NET framework, the same as C#, the language used by Unity3D. It is clear, then, that we could use F# in Unity. And, in fact, we can with moderate easiness.
Should we? How easy is that? answering these questions is the goal of this article.
The State of F#
F# is a very pleasant language. It combines the strengths of functional language such as OCaml, with a real practical sense. In fact, F# is functional-first, but if the problem requires it, it allows you both Object Oriented and procedural paradigms. If you want to know more on F#, go here.
In my opinion, the biggest problem with F# was the environment (the platform where it runs, the tooling, everything). F# was great if you used Windows and Visual Studio. Everything else was a nightmare.
Then improvements arrived. It was possible to create a project from the command line without requiring Visual Studio. But it was still not perfect. Creating a project was slow, each project occupied something like 250Mb for a “hello world” project. It was messy, not for me.
Then .NET Core 2.0 arrived. I tried F# recently and it much better. The dotnet
CLI utility is great. It is on par with other package manager and building tools. The same “Hello World” project now occupies 2Mb.
I am very happy with that. .NET Core is still not supported by the full ecosystem, but for my needs, there is no friction between me and an F# experience.
Use F# in Unity, The updated way
But let’s come to the meat. How to use F# in Unity? It is “easy”. On the internet there are a lot of guided but some of them are not updated, some of them require/assume Visual Studio, others just do not work. I present to you the simplest way possible using only the command line interface (and unity).
First step, let’s create a new library
|
|
Open Library.fs
and write your code. In this case, just a simple library with a function that sums two numbers.
|
|
Then, let’s open sharptest.fproj
and change the TargetFramework
into net45
(for the moment, this works in Unity). I think this is changed or will change in Unity 2018, but for now, let’s stick to the known path.
|
|
We just need to build and publish our library.
|
|
Now we need to move to Unity. Go in the folder sharptest\bin\Debug\net45
andcopy FSharp.Core.dll
and sharptest.dll
. These file represent our library. Paste these dlls into Unity asset folders.
Because I wasn’t able to target .NET 3.5 assembly, we need to enable experimental support for .NET 4.5 in Unity (Edit → Project Setting → Player, then in the panel look for “Scripting Runtime Version”).
That’s it. You can just use this library as usual (* with limitations!):
|
|
Open Issues and Discussions
As you can see above, use F# in Unity is a project inside a project. You need to compile first the F# project and then import the F# output into Unity. This is a bit cumbersome, but it is not so bad. In the end, you can always automate a simple compile-copy loop.
The real problem is that F# is still a second-class citizen and there are many things that don’t work out of the box. When I asked on Twitter about the state of F# in Unity I get some interesting responses. Two of them are the most interesting.
The first and most enduring difficulty is how Unity cordons off MonoBehaviour and ScriptableObject constructors. Couple that with the fact that any component on a game object must derive from one of those two classes, and your F# code 1/n
— Dan L (@danl2620) 15 aprile 2018
The first one is from Dan Liebgold, CTO of Wonderstorm. The Twitter thread is interesting. In short, most of the problems come from the interaction surface between Unity framework and F#. If you are doing a plain library as I did before, there almost none problems. You are just doing a library that takes input and returns output. But if your F# sharp library needs to interact with Unity more in deep (that is, derive from MonoBehavior/ScriptableObjects) then the all process is going to be more complicated. For instance, there is no nice F# compatible interface so you need to plug in into the C# interface. But C# has nulls and other things that are not idiomatic in F#, so you need to wrap everything in boilerplate.
Another problem is about IL2CPP, the backend converting .NET assembly into C++. This process is required for many platforms (iOS and WebGL, to name a few) and it does not officially support F#-generated assembly. For instance, fprint
just crash at runtime.
Officially, F# is not supported. That said, we try to keep il2cpp working with F#. We have a test suite for F# and things are generally OK aside from the lack of value type generic sharing
— Mike Voorhees (@mvoorhees13) 16 aprile 2018
The second comment I want to share is from Mike Voorhees, a software developer at Unity Technologies. This Twitter thread gives us more insight on F# in Unity. We know more details on the printf
problem, but, more importantly, we know that F# is not supported but it is not ignored. There is people that try to keep compatibility as much as possible, and that’s nice.
Conclusions
**In the end, F# in Unity is still a pioneering challenge. My idea is that this is a burden worth only if you are already using F# extensively in other parts of your game.** For instance, you may use F# for your game server architecture. In that case, the ability to share big chunks of code between server and client is worth the effort of dealing with these rough edges.Functional programming in games is an interesting topic. I am pretty confident that F# and Unity synergy may be an exiting experience. But we are not there yet. At least for the general public.
But try F#. It is super-fun.
PS: I’ll try to keep an eye on this problem. Thing are much better than an year ago. I hope things will get even better. I something new will happens, I’ll keep you updated.