Saturday, May 29, 2021

Sum types in Go

One thing I always missed in Go was sum types. I’ve seen some discussion before. Although Go doesn’t have this as an explicit, native feature, I found a pattern that suits my needs by defining types and interfaces.

In the example below, I simulate a function that would load application resources, which can be extracted by ID, position or a string identifier. First, we define the interface and the subtypes:

type (
	// Variant type for: ResId, ResPos, ResStr.
	Res interface{ implRes() }

	ResId  uint32
	ResPos uint32
	ResStr string
)

func (ResId)  implRes() {}
func (ResPos) implRes() {}
func (ResStr) implRes() {}

The isRes() function acts like a “tag” for each subtype.

Now, a function that receives the variant type:

func LoadResource(variant Res) {
	switch v := variant.(type) {
	case ResId:
		println("ID", uint32(v))
	case ResPos:
		println("Position", uint32(v))
	case ResStr:
		println("String", string(v))
	default:
		panic("Res does not accept a nil value.")
	}
}

Usage is now trivial:

LoadResource(ResId(2001))
LoadResource(ResPos(4))
LoadResource(ResStr("MY_ICON"))

It’s clean and it works remarkably well. I applied this technique in my Windigo library.

Monday, May 17, 2021

Registering file associations in Windows

I always used FileTypesMan to register the Windows file associations. But after Windows 7 or so, some associations simply refused to work, leaving them wrong. In Windows 10, this problem worsened.

Today, after digging the associations created by Reaper, I figured out one of the correct ways to register a file association – there are other exotic ways too, which I couldn’t figure out yet.

These are the Windows Registry entries that must be created:

HKEY_CLASSES_ROOT\.fuu\
    (Default) REG_SZ Fuu.File
    Content Type REG_SZ text/plain
    PerceivedType REG_SZ text
HKEY_CLASSES_ROOT\Fuu.Type\
    (Default) REG_SZ A fuu file.
    DefaultIcon\
        (Default) REG_SZ C:\Temp\fuu.exe,0
    shell\
        (Default) REG_SZ open64
        open64\
            (Default) REG_SZ Open file in Fuu
            command\
                (Default) REG_SZ "C:\Temp\fuu.exe" "%1"

And these entries map correctly in FileTypesMan, which can be used to further changes.

Note that Content Type and PerceivedType will automatically create “Open” entries mapped to default applications, so you probably won’t want those. In its simplest form, this will work:

HKEY_CLASSES_ROOT\.fuu\
    (Default) REG_SZ Fuu.File
HKEY_CLASSES_ROOT\Fuu.Type\
    (Default) REG_SZ A fuu file.
    DefaultIcon\
        (Default) REG_SZ C:\Temp\fuu.exe,0
    shell\
        open\
            command\
                (Default) REG_SZ "C:\Temp\fuu.exe" "%1"

Thursday, May 13, 2021

The ghastly button focus

During my 20 years or so writing Win32 programs, I always relied on SetFocus to focus a control. However, I always noticed a weird behavior on push buttons regarding the BS_DEFPUSHBUTTON style, which was never right. In fact, I remember one of the past WinLamb incarnations which I implemented some trick involving changing the button style when setting the focus.

Anyway, now I found out how to properly set the focus on a control, and it does not involve SetFocus, but rather the WM_NEXTDLGCTL message:

SendMessage(hParent, WM_NEXTDLGCTL, (WPARAM)hButton, MAKELPARAM(TRUE, 0));

And the push button magically sets its own style correctly.

Wednesday, March 31, 2021

Fixing Cargo authentication on GitHub

Today, while performing tests before publishing the first version of WinSafe, I stumbled across a problem I had with Go a few weeks ago. It was caused because GitHub no longer accepts user/password authentications, so everything must be done via SSH. I solved the problem by adding some lines to my ~/.gitconfig file.

But Cargo still cannot fetch packages.

After a lot of digging, I found a setting that finally worked. It involved adding another filter to ~/.gitconfig, which now looks like this:

# Force SSH instead of HTTP
# https://stackoverflow.com/a/27501039/6923555
[url "ssh://git@github.com/"]
	insteadOf = https://github.com/
	
# But crates.io needs to pass
# https://github.com/rust-lang/cargo/issues/8172#issuecomment-659066173
[url "https://github.com/rust-lang/crates.io-index"]
	insteadOf = https://github.com/rust-lang/crates.io-index

The “crates.io” directory was updated and I could use an external crate, something that will be needed when I publish my own.

As a side note, all downloaded crates are stored in ~/.cargo/registry/ directory, which can be safely wiped out to clean the cache.

Thursday, March 25, 2021

Displaying current Git branch in Bash prompt

I decided to show the current Git branch at my bash prompt whenever I’m at a directory which contains a repository. I found a rather convoluted Bash-esque solution, which I adapted to myself:

gitbranch() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ \1/'
}
#export PS1="\u@\h \[\e[32m\]\w \[\e[91m\]\$(gitbranch)\[\e[00m\]$ "
export PS1="\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\[\e[33m\]\$(gitbranch)\[\e[00m\]\$ "

It’s compact and it works as intended.

Thursday, February 18, 2021

Using local dependencies with Go modules

Go 1.16, released this week, deprecated GOPATH. I used it extensively to develop my libs before publishing them, but now I’m forced to convert them to modules, which work with remote repos by default. However, there’s a way to work with local dependencies.

As I found here, we can instruct Go toolchain to search for a local repo, instead of a remote one by using this command:

go mod edit -replace github.com/username/repo=../repo

This changes the go.mod file. Now, to clean up the go.sum file, run:

go mod tidy

After that, you should be able to use a local dependency just like the old GOPATH days.

The downloaded files are still cached, though. To finally clean the entire cache, run:

go clean -cache -modcache

Modules eventually needed by other applications will be downloaded again when due.

Tuesday, January 5, 2021

Downcasting boxed errors in Rust

Today I was trying to write polymorphic error handling in Rust, something achievable with dynamic_cast in C++, and incredibly easy in Go. In Rust, of course, it’s overcomplicated.

After a couple frustrating hours of searching with no success, I stumbled upon the downcast_ref method of the Error trait, which finally allowed me to write what I wanted. Oddly enough, I couldn’t find this solution anywhere.

Note that the String concrete type cannot be retrieved.

Playground link here.

Friday, December 11, 2020

Cleaning up a Git repository

Sometimes, after you mess up too much with your Git repository, it ends up with a couple useless objects, which are no longer referenced anywhere.

I created this alias a while ago, collected from sources I don’t remember anymore, to perform a cleanup in the repository. It’s particularly useful right after a git fetch:

alias gitcleanrepo='git fetch origin --prune && git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@"'

Tuesday, November 24, 2020

Inserting auto IDs in Oracle

When dealing with tables with an auto-incremented ID field, Oracle requires an special syntax if you’re about to insert data manually. You must directly call the name of the sequence of that table, followed by a special field:

INSERT INTO person (id_person, name)
VALUES (sq_id_person.NEXTVAL, 'John')

Note that the name of the sequence is actually arbitrary.

Friday, October 16, 2020

Validating lambda signatures in C++17

WinLamb, as the name itself implies, is heavily based on lambda functions. While searching a way to enforce the lambda signatures in the upcoming C++17 release, I received an incredible answer on StackOverflow:

#include <functional>
#include <type_traits>
	
template<typename F>
auto foo(F&& func) noexcept ->
	std::enable_if_t<
		std::is_same_v<
			decltype(std::function{std::forward<F>(func)}),
			std::function<void(int)>
		>, void
	>
{
	func(33);
}

Up to this point, I was completely unaware of the existence of trailing return types in function declarations.

The validation is extremely restrict, serving my purposes perfectly. And it seems that the upcoming C++20 concepts feature can simplify it quite a lot.

Thursday, August 6, 2020

SFINAE and enable_if

Today, while researching for the upcoming C++17 version of WinLamb, I was rethinking the idea of restricting the allowed types on a template argument. That’s an SFINAE thing, scary to many people – including me sometimes, in my love-hate relationship with advanced C++ stuff.

The thing is that I ended up writing a working piece of code using std::enable_if to restrict a template argument, and I’m quite proud of it.

#include <type_traits>

struct One { int num; };
struct Two { int num; };
struct Tre { int num; };

template<
  typename T,
  typename = std::enable_if_t<
    std::is_same_v<T, One> ||
    std::is_same_v<T, Two>
  >
>
void foo(T& o) { ++o.num; }

int main() {
  One o;
  foo(o);
  return 0;
}

In the code above, One and Two classes will work with foo(), whereas Tre will not compile, despite being exactly like the others.

Thursday, June 25, 2020

CSS folded poster effect

Yesterday I just stumbled across this incredible CSS work, which makes a picture look like a folder poster on Reddit. The CSS was somewhat overengineered, so I removed a bunch of stuff and fixed some parts, and the result is now pretty usable.

The border is set by the padding attribute, and may need to be adjusted according to the image size. The image size itself cannot be properly set, or the effect goes nuts – if you want to resize the image, resize the image file itself.

I hope to use it somewhere, because it’s really cool. Props to the dude who did it.