So, I finally did it.

Back when I was in college (or university, whatever floats your boat), I made a Windows application called DeskHubSharp. What this application did was it grabbed user data from GitHub, including repositories from the user, and displayed the data. You were allowed to view detail about the user, view detail about a selected repository, download a branch from the repository, and view the repository’s GitHub page. However, this application has been largely unmaintained.

There were some drawbacks to this application. For starters, it only worked on Windows (yes, I know, shocker). This happened because the underlying framework was Windows Presentation Foundation (or better known as WPF). Just running on Windows wasn’t enough for me. While I was developing the application, I had to use an application called Parsec to develop and run the program on Windows. Even though I still use Parsec to this day, developing and running the application was kind of tedious. Several issues popped up as well, like the repository sorting functionality was broken. I’d go and sort from least to most stars for all of the repositories, and it would sort correctly, but viewing the detail on a particular repository would pick the repository four indexes behind the repository I’m actually trying to view. This happens with every sorting option in my app.

However, there is only one very important question on everybody’s minds: What am I going to call the revived project? Don’t worry, I came up with something - I have dubbed it DeskHubSharp Revised.

Don’t let any kind of developers name or title anything, for your own sanity.

One true love

I had stated in the past I would proceed with some next steps. One next step was build the application in Avalonia, a user interface toolkit that was similar to WPF, but vastly different. While WPF used a Windows-only drawing library to draw windows, buttons, labels, and lists, Avalonia used a drawing library called Skia (SkiaSharp to be exact). This means that Avalonia can not only draw on Windows platforms, Avalonia can draw on macOS and Linux platforms. Additionally, Avalonia can also draw on iOS, Android, and even to the web through WebAssembly. Another next step was trying interoperability with the application. Enter F#.

Exploration

Why F#? Well, it’s part of the .NET framework, so I don’t have to learn a whole different standard library/framework. In my Android class, I had to learn not only the Android libraries, but I also had to learn the Kotlin standard library as well (and a part of Java’s standard library as well because some of Android’s libraries are tied to it). For example, you call an IEnumerable or an ObservableCollection in F# just like you would in C#, which is really handy, especially when interoperability is concerned. Additionally, another next step was to mess with F#. I have never messed with F# before and I still kind of like C# still (sorry Dave) so I thought it would be nice to give F# a fighting chance (because, you know, I’m a language nut). The last step was to port it over to .NET Core (which then it is now just .NET, not Core or Framework. Just .NET) to help with compatibility.

Onward to new and modern technology

Let’s start with the easy stuff. Porting to .NET 6 was a piece of cake. A simple copy and paste from the old application to the new application did the trick. Next, came the ripping and tearing of WPF and putting Avalonia in it’s place. This quite straightforward to do as well. I created new Avalonia windows and then copy-pasted the content from the WPF windows. I did the same thing when it came to the code-behind. Intellisense in VS Code was smart enough to realize I was missing some Avalonia classes so I added those in. However, that is were the easy stuff ended.

I would be wrong in saying that Avalonia is a drop-in replacement because it’s not. I had to do some manual adjustments on my end. For example, to show a window, I couldn’t do this.ShowDialog() like you would in WPF. You have to call the parent window inside the ShowDialog call: this.ShowDialog(this) or just call this.Show() instead. Another example is with the ListBoxes. You can’t call the property ItemsSource like you would in WPF, you have to call the property Items instead. These changes, among others, are not too bad but it would be nice if everything about Avalonia was the same as WPF.

Porting to F#

More ripping and tearing coming your way because it’s time for me to talk about F#, and what I experienced with the language and it’s tooling. F# has quite the syntax and it’s vastly different than C#’s syntax. So, I had to learn it for the models. In C#, the models are classes, but in F#, those classes are types, specified with the type keyword. Let me show you what I mean:

type Email() =
    let mutable _toEmail: string = "wjmiller2016@gmail.com"
    let mutable _fromEmail: string = "wjmiller2016@gmail.com"
    let mutable _password: string = "password"
    
    member this.ToEmail
        with get() = _toEmail
        and set(value: string) = _toEmail <- value
    member this.FromEmail
        with get() = _fromEmail
        and set(value: string) = _fromEmail <- value
    member this.Password
        with get() = _password

The above example is a model for my feedback functionality inside the application.

The let keywords are variables inside a type, kind of like private fields, which is what these variables serve as, or any kind of variable for that matter. The mutable keywords are for letting the variables change values. By default, F# has immutability, meaning that every variable won’t change from underneath you unless explicitly defined with the mutable keyword. This concept is similar to Rust’s immutability concept and it’s mut keyword. The member keywords are for properties, and they can defined with getters and setters, like what’s shown above. Don’t worry, though, you don’t have to add getters and setters. I had to write custom code for my backing fields. It took a while to find my ground when it came to what a property was, what a field was, and variable was. This was immensely helpful along my journey. Once I knew what was what, it wasn’t too hard to figure out what I had to do, as far as storing the GitHub data is concerned.

Tools for a more civilized age

Let’s talk tooling. F# is great and all but I could not find any serialization tool out on the Internet. I’m not talking about Newtonsoft.Json, that’s a great tool, but I’m talking about JSON files and transforming them into objects/types for you. It’s similar to this website here. I had to write every source file by hand. Don’t try it. I’m so irritated by this that I might have to write a tool to do just that. There’s some other tools I would like as well, like a C# to F# converter, but I’d imagine that’s quite the ambition to take that on. Since C# and F# are both .NET languages, it shouldn’t be that hard, right? Right? All-in-all, I think F# is an alright language. There’s still so much I have to learn from it, though. Maybe writing the serialization tool in F# will help.

Existing cruft

What about existing bugs that need to be ironed out? Well, since I don’t know how the bugs even cropped up over the three week course of my developing craze, I will try my best to get rid of existing bugs in the future, as well as squashing new bugs that come my way.


For source code on DeskHubSharp Revised, see this.