Programming

Millie 0.9.6, or “installers are hard”

I’ve been terribly busy with work lately and so I haven’t really had much time for my side projects. I did however managed to get a new version of Millie out of the door.

Got get it here.

Changes are mostly infrastructural though.

User “visible” changes:

  • Add .deb installation files for Linux
  • Add support for electron-builder
  • New settings system
  • Fix missing icon on Win64 installer
  • Split generation of 32- and 64-bit installers on windows

Minor changes and fixes

  • Merge branch ‘builder’ of github.com:robteix/millie
  • Ignore backups
  • Add missing dependency
  • Ignore main.js.map
  • Remove warning on unknown props
  • Cleanup
  • Move background declaration to MillieView
  • Stop loading old settings
  • Add script to generate release files
  • Remove log file left from first commit

That said, this release reminded me of how hard installers are to get right. Actually, they’re hard to do at all.

MacOS installers can basically only be made on macOS due to there not seeming to be decent implementations of DMG anywhere else. You can compile and create a ZIP file with your binaries, sure, but who wants that? To create a nice DMG, you need to be on macOS.

Windows is also hard to do in other systems. Not impossible, just annoying. You can get by with Mono in Linux or macOS but you need to get around a bug here and there. It works though.

Linux installers (meaning .dpkg and .rpm) are easy to do in macOS but barely doable on Windows.

In practice you end up having to create each installer on its own environment. Linux and Windows are easy to do with VMs, but you’ll need a macOS box eventually.

Windows has its own share of problems though. I hear they’re working on finally fixing their dumb limitations on path length but it’s definitely not there yet. This is important when working with things like npm that create paths hundreds of levels deep. Trying to something simple like deleting a node_modules directory on Windows is an exercise in frustration.

The installers for this release were all created in a Linux VM though. It was the closest thing I got to building it all in a single platform. No DMG for macOS though.

How do I add an unknown attribute to an element in ReactJS?

There’s this project I’ve been working on in ReactJS and Chrome and I needed to use a <webview> component. In case you’re not familiar with <webview>, it looks something like this —

<webview src="https://robteix.com"></webview>

One of the coolest features of <webview> is the ability to isolate scope or partition it. When you use a partition, all cookies, local and session storage, etc, will be stored separately from other partitions. All you need to do is add the partition attribute. So I had something similar to this inside one of my components —

return (
 <webview id="foo" 
 src="https://somewebsite.com/"
 partition="persist:foobar" />
);

To my surprise, multiple <webview>s were sharing the same session data. Not good. A quick glance in the app storage directory told me that no partition was being created. What’s wrong?

We can look at the HTML output for hints —

<webview id="foo" src="https://somewebsite" class="MyComponent__component___3U2KV" data-reactid=".0.0.0.2:$MyComponent.0" tabindex="-1"></webview>

No partition to be found. The reason is React doesn’t know what to do with that attribute and as a result it is not output. There are good reasons for this, but the main one is that properties may (and often do) work differently accross browsers and React needs to be able to deal with this.

But how can we add the attribute that we need then? You could add some JavaScript to get the element but that’s not very reactive. The reactive way to do this is to leverage ref, which can provide a reference to an element.

<Element ref={somevar} />

In this code, somevar will hold a reference to <Element>. Better yet, just use a function instead.

<Element ref={function(e) { e.Something(); }} />

Or in ES6 syntax.

<Element ref={(e) => e.Something() } />

Which finally takes us to our problem: how do we add the partition attribute? Easy peasy.

return (
 <webview id="foo" 
 src="https://somewebsite.com/"
 ref={elm => elm && elm.setAttribute('partition', 'persist:foobar')} />
);

And that’s it, a simple way to add unknown attributes to elements in React.

Clashing method names in Go interfaces

I wrote about how the Go and C# compilers implement interfaces and mentioned how C# deals with clashing method names but I didn’t talk about how Go does it, so here it is.

Two interfaces with the same method name that need to behave differently is very likely a sign of bad API design and we should fix it instead. But sometimes we can’t help it (e.g. the interfaces are part of a third-party package). How do we deal with it then? Let’s see.

Given two interfaces

type Firster interface {
    DoSomething()
}

type Seconder interface {
    DoSomething()
}

We implement them like this

type MyStruct struct{}

func (ms MyStruct) DoSomething() {
    log.Println("Doing something")
}

We can run this little test here to verify that MyStruct implements both interfaces.

But what if we need DoSomething() to do something different depending on whether MyStruct is being cast as Firster or Seconder?

Go doesn’t support any kind of explicit declaration of interfaces when implementing methods. We can’t do something like, say

type MyStruct struct{}

func (ms MyStruct) Firster.DoSomething() {
    log.Println("Doing something")
}

func (ms MyStruct) Seconder.DoSomething() {
    log.Println("Doing something")
}

That won’t work. The solution is to wrap MyStruct with a new type that reimplements DoSomething(). Like this

type SeconderWrapper struct {
    MyStruct
}

func (sw SeconderWrapper) DoSomething() {
    log.Println("Doing something different")
}

Now when we need to pass it to a function expecting Seconder, we can wrap MyStruct

ms := MyStruct{}
useSeconder(SeconderWrapper{ms})

That will run the DoSomething() from SeconderWrapper. When passing it as Firster, the original DoSomething() will be called instead. You can see this in action here.

Interfaces in Go and C#

I make no secret of the fact that I love Go. I think it’s a wonderfully designed language and it gave me nothing but pleasure in the years I’ve been working with it full time.

Now however I am working on a project that requires the use of C#, which prompted me to realize something.

When people ask about Go, most people talk about channels and concurrency but I think one of the most beautiful aspects of Go is its implementation of interfaces.

To see what I mean, let’s define a simple interface in Go.

type Greeter interface {
    Hello() string
}

Now say we have a type that implements this interface

type MyGreeter struct {}

func (mg MyGreeter) Hello() string {
    return "Hello World"
}

This is it. myGreeter implicitly implements the Greeter interface and we can pass it along to any function that accepts a Greeter.

func doSomethingWithGreeter(g Greeter) {
    // do something
}

func main() {
    mg := myGreeter{}
    doSomethingWithGreeter(mg)
}

The fact that the implementation is actually important, but we’ll get to that. Let’s first do the same thing in C#.

interface Greeter
{
    string Hello();
}

And then we create a class that implements the interface.

class MyGreeter
{
    public string Hello()
    {
        return "Hello world";
    }
}

We quickly find out that the compiler doesn’t like this.

public static string doSomething(Greeter g)
{
    return g.Hello ();
}

public static void Main (string[] args)
{
    MyGreeter mg = new MyGreeter ();
    doSomething (mg);
}

The compiler complains that it cannot convert MyGreeter to type Greeter. That’s because the C# compiler requires classes to explicitly declare the interfaces they implement. Changing MyGreeter as below solves the problem.

class MyGreeter : Greeter
{
    public string Hello()
    {
        return "Hello world";
    }
}

And voilà, everything works.

Now, we might argue that it is not much different. All you have to do is to declare the interface implemented by the class, right? Except it does make a difference.

Imagine that you cannot change MyGreeter, be it because it’s from a third-party library or it was done by another team.

In Go, you could declare the Greeter interface in your own code and the MyGreeter that is part of somebody else’s package would “magically” implement it. It is great for mocking tests, for example.

Implicit interfaces is an underrated feature of Go.

Update: someone on Twitter pointed me to the fact that C# not only also has implicit interfaces but that this is the default state of things. That is true in a literal sense, but it’s not the same thing.

Imagine in our C# above, we have a second interface.

interface IAgreeable
{
    string Hello();
    string Bye();
}

(Yes, I was also told that in C# we should always name interfaces like ISomethingable. I disagree but there it is.)

We then implement our class thusly

class MyClass : Greeter, IAgreeable
{
    public string Hello() {
        return "Hello world";
    }
    public string Bye() {
        return "Bye world";
    }
}

It now correctly implements both interfaces and all is well with the world. Until, that is, the Hello() method needs to be different for each interface in which case you will need to do an explicit implementation.

class MyClass : Greeter, IAgreeable
{
    string Greeter.Hello() {
        return "Hello world from Greeter";
    }
    public string Hello() {
        return "Hello world from !Greeter";
    }
    public string Bye() {
        return "Bye world";
    }
 }

And then the compiler will call the appropriate Hello() depending on the cast.

public static string doSomething(Greeter g)
{
     return g.Hello ();
}
public static string doSomethingElse(IAgreeable g)
{
    return g.Hello ();
}
public static void Main (string[] args)
{
    MyClass mg = new MyClass ();
    Console.Out.WriteLine(doSomething (mg));
    Console.Out.WriteLine(doSomethingElse (mg));
}

This will print

Hello world from Greeter
Hello world from !Greeter

Personally I consider two interfaces with clashing method names that need to behave differently a design flaw in the API, but reality being what it is, sometimes we need to deal with this.

Github’s Swift Style guide

Github has published a Swift Style Guide:

When you have to meet certain criteria to continue execution, try to exit early. So, instead of this:

if n.isNumber {
    // Use n here
} else {
    return
}

use this:

guard n.isNumber else {
    return
}
// Use n here

Feels very Go-like.