
Porting 4.5K lines of C to Go - ingve
https://blog.kowalczyk.info/article/wN9R/experience-porting-4.5k-loc-of-c-to-go-facebooks-css-flexbox-implementation-yoga.html
======
to3m
> As far as I can tell you can’t step through tests in the debugger

Rant time. What to do when you write a test framework.

1\. When test fails, print everything possible: desired expression, desired
value, actual exression, actual value, line and file of failing call. When
printing line and file, make the format configurable, with the default being
the prevailing standard for the system, so that people can get clickable links
in their text editor or terminal with a minimum of hassle.

About 90% of the time, this will give people everything they need in order to
at least get started on fixing the failed test

2\. Don't make it hard to use the debugger. The remaining 10% of the time,
people will need to step through the code. Some measurable fraction of the
other 90%, they'll also end up needing to do this, because it looked like it
was something simple but actually it was more than that. So don't make this
hard

3\. See steps 1 and 2

This might sound obvious, but it clearly isn't, because I've used several test
frameworks that make running in the debugger rocket science, and print
literally nothing but your own message (if even that) when the test fails.
Like, you do 'assert.equals(x,y)', and it doesn't even show you what the
values of x and y are, let alone figure out that maybe "x!=y" would be an
obvious thing to print.

This may not sound like a big deal with my stupid little example, but after
you've written several tens of these you will start to see my point.

~~~
gouggoug
Slightly related:

The lack of an easy to use debugger is a huge issue for me when working with
go.

Coming from PHP, I spend 90% of my time in the debugger running my code line
by lines (with xdebug coupled to phpstorm).

A debugger is _especially_ useful when working with other's people code and
large softwares. For example, contributing to large Go projects like
Kubernetes can be daunting due to the very steep learning curve. This curve
would be greatly reduced if we had a good reliable go debugger, which doesn't
seem to be the case at the moment. (I'm aware of delve, but last time I
looked, it was still fairly complicated to have it work).

~~~
abledon
How is the debug experience in elixir compared to go ?

~~~
zeptomu
I have to admit, although I use domain specific debuggers sometimes (gdb,
debuggers of IDEs), I mostly debug via print-statements, as it just works in
most scenarios.

Am I missing out? AFAIK step-back debuggers are still more research (I think
Elm has something like this), but otherwise I just want to have system
snapshots and there print($foobar) works very well for me across languages.

~~~
justinclift
Yeah, you're missing out. :)

Print statement style debugging can (with effort) get a lot of stuff figured
out.

But :), it's often fairly slow to go through that iteration cycle with non-
trivial bugs, compared to using a debugger.

With a debugger, you start from the same place in your code you'd put your
print statements. But instead of modifying the code to spit out values, the
debugger will pass control of the running program to you. You can then go
forwards through your program, seeing how the variable values change, which
branches are taken, etc.

It'll get you to the same end result as the print statements, but faster.

Also, for complicated/hairy/weird bugs, being able to follow the actual
execution can be enlightening which print statements don't really do.

~~~
zeptomu
:)

Some time ago I did more Java and used Eclipse heavily and its debugger was
really nice, so I share your opinion that you get nice features.

However if you are working on a project (at least that has been my experience
so far) that does a lot of multiprocessing (let's say a web service with a
processing scheduler in the background calling into processes implemented by
different languages) and you may have bugs on several layers using different
programming languages, I like the fact that I can use the same concept for all
of them and write some custom "debug.log" that I can later analyze (obviously
good logging in the first place can help a lot).

But I may check them again: Do modern debuggers work across languages
(assuming available source), let's say web-request -> Python -> FFI -> C++?

Previously such scenarios have been non-trivial to debug (although there are
some pretty advanced multithreaded code analyzers now), but maybe it has
changed for the better.

~~~
justinclift
> But I may check them again: Do modern debuggers work across languages
> (assuming available source), let's say web-request -> Python -> FFI -> C++?

Gah... no idea. I'm still doing mostly doing single language stuff. :D

The kind of request path you're mentioning there... yeah, I'd probably go back
to using print statements too, as I'd have no idea how to hand off from one
language to another in some kind of meta-language-debugger. Which would
actually be nifty if it exists.

------
jclulow
> Too many people have a bad habit of including “go” in their repository name,
> presumably to not confuse people with non-go version of the code.

Note that this is actually a _perfectly reasonable thing to do_. If I had two
clients for some particular API, one written for Node and one for Go, it
absolutely makes sense to name them "node-whatever.git" and "go-whatever.git".

Part of what makes naming things hard is needing to come up with a more
"creative" name for every little module, especially once you throw in the
constraint that apparently eight characters is too long and four characters is
just right.

~~~
kjksf
It might be necessary to resolve naming conflicts but it's not good.

In Go, package name should be the same as repo name.

Most cases that I've seen are not including "go" in repo name to resolve
naming conflict but "just because", possibly cargo-culting others that did it.

~~~
jclulow
What if those people or organisations have a lot of repositories and they want
to use a naming convention that reflects that maybe, just maybe, _only a
subset of their code is written in Go_?

I recognise that you don't speak for the entire Go community, but frankly this
kind of over-prescriptive preference presented as the only possible way
forward is oddly common in what often seems more like a church than a
programming language ecosystem.

Go is just a tool, like any other. If I happen to use git for versioning
that's my choice, and I (and everybody else) can and should name and arrange
repositories _as is convenient_.

There is no "in Go" to be had here; merely "in my project as makes sense for
me".

~~~
ovao
> What if those people or organisations have a lot of repositories and they
> want to use a naming convention that reflects that maybe, just maybe, only a
> subset of their code is written in Go?

I'm not sure I understand how that's an argument in itself for using "go-" or
"-go" (or some other version) in a package name. It results in a lack of
clarity in how to reference the package: the hypothetical
"github.com/stripe/stripe-go" import path _probably_ (and almost certainly)
introduces the "stripe" package name, but the the discordance between what you
write as an import statement and by what name the package is referenced is
unconventional and strange.

There are certainly times when it makes sense. And I agree with the idea that
an organization, in most cases, shouldn't come up with a unique name for the
Go implementation of, say, an API wrapper, just to satisfy Go convention. But
generally speaking the convention should be followed not simply because it's
prescribed but because it's sensible to avoid that disconnect between the
import statement and the package name.

------
krylon
> However, win32 doesn’t have anything to help you layout things on the
> screen. Manual positioning is painful.

Ooooh, yes, I remember that. My first experiences with GUI programming was a
tiny little of Perl/Tk, then Gtk 2 in Perl, Python, and Ruby.

And then I started working as programmer, doing maintenance on an line-of-
business application suite written in C/Win32, and I was shocked people would
actually put up with this. Fortunately, the overwhelming majority of my work
dealt with the deepest guts of those programs, and I only needed to deal with
Win32 directly on a few occasions.

~~~
sjmulder
I've started writing some Win32 code for fun and like you I found it a whole
different experience from GTK and such. It really is an API rather than a
toolkit.

Take scrolling. Scroll bars are provided when requested, but all the
interactions have to be implement by the application. There's no 'scroll view'
with standard behaviours. This means Microsoft can't easily add new scrolling
behaviours as we see with the messy situation around high precision trackpads
and touch.

Compare this to Cocoa with its auto layout, data binding and even document
lifecycle management.

On the other hand, with Win32 I rarely find myself fighting the toolkit. I'm
in control.

Backwards comatibility is also amazing. With my little project I'm targeting
Windows 3.1 through Windows 10 with a single binary! I expected most of my
effort to go towards supporting old OSes, but in reality I spend more time on
modern features like proper per-monitor DPI suport, the gazillion different
scrolling behaviours and (conditionally loaded) GDI+ and Direct2D
implementations.

Another delightful aspect, although again it comes the beforementioned price,
is the speed. My little utility starts instantly and won't skip a beat when
you frantically shake the resize grip. Compare that to even the simplest UWP
XAML app.

~~~
krylon
> Another delightful aspect, although again it comes the beforementioned
> price, is the speed.

That is true, with only a little care, one can write insanely fast and
responsive UIs in Win32.

------
thelazydogsback
> "Go doesn’t support xor (^) and or (|) operator on bool. As it turns out,
> they are not neccessary. x ^ y is the same as x != y. a = a | b can be
> written as: if !a && b { a = true }"

Well, you don't _need_ subtraction, division or multiplication either (or any
number more than 1!), but they're certainly nice to have. Go has some nice
qualities, but its choice of omissions continues to fascinate me.

~~~
tomjakubowski
You can put (some of?) your fascination to rest, Go has ||.
[https://play.golang.org/p/_GKbk_GUAe](https://play.golang.org/p/_GKbk_GUAe)

------
assafmo
Sounds very uneventful... A few porting bugs and language differences but not
a lot.

At least it sounds like a great way to learn about flexbox internals.

~~~
pacaro
This was my take too. Some reinforcement about the utility of tests. 4.5k is a
relatively small amount of code (particularly in C or similar)

------
st3fan
> As far as I can tell you can’t step through tests in the debugger

Really? In Visual Studio Code this is as simple as:

1) Set a breakpoint in your test

2) Hit the "Debug Test" button

See
[http://wopr.norad.org/~stefan/delve.png](http://wopr.norad.org/~stefan/delve.png)
for this in action. Look how great this looks. And how you can see all your
variables in the upper left section. How you can expand structs and inspect
them.

In my experience this works really really well.

~~~
lobster_johnson
Delve and the VSC integration is great. Just note that it's historically been
quite buggy and unstable. Worse, for a long time it wasn't practically
possible to use Delve on macOS due to changes introduced in 10.12 [1] [2]. It
should be better now, though.

[1]
[https://github.com/derekparker/delve/issues/645](https://github.com/derekparker/delve/issues/645)

[2]
[https://github.com/aaronhackney/delve_on_mac/blob/master/REA...](https://github.com/aaronhackney/delve_on_mac/blob/master/README.md)

------
tigershark
This is what really struck me: "The API is still a bit awkward by Go
standards. Too many methods, _not enough direct access to variables_ " Does he
really mean that proper go code has direct access to fields rather than
encapsulating them???

~~~
kjksf
I would phrase it like that: most languages (C++/Java/.NET) have unhealthy
obsession with creating unnecessary setters/getters, paying for it with
increased compile time, code bloat, slower code.

In Java/C# land refactoring tools even give one-click access to "create me
some setters/getters".

This is not to say that abstracting access with functions has no place, but if
all they do is get/set the value, they are unnecessary.

~~~
taspeotis
> paying for it with increased compile time, code bloat, slower code.

Auto-properties in C# are one line of code, same as fields, and the
getter/setter methods should always be inlined which turn them into field
accesses anyway. So I'm not sure how that would affect compile times or lead
to slower code in anything but some pathological use case. Or DEBUG, but at
that point all performance bets are off.

(Technically Microsoft _can_ get worse performance on properties vs. fields
when using NGen - that's why they have TargetedPatchingOptOutAttribute - but
that doesn't apply to regular, non-Framework assemblies.)

As for code bloat `public int SomeValue { get; private set; } = 6;`
encapsulates a publically read-only/privately mutable property with a default
value quite concisely...

~~~
zaroth
(smacks forehead)

Wait, wait, since _when_ can you put the default assignment right there on the
same line? Go ahead, say _since always_... I dare you.

Edit: Apparently this came in C# 6.0 (July, 2015). Ok, now I don't feel so
bad. :-)

On a separate note, C# might not sexy or even that popular, but I really enjoy
coding in it, and the continuing evolution of the syntax is a joy.

~~~
shpongled
It really is a joy to program in. I fought it off for the longest time (I like
regular ole C, python, dabbled in Java long ago), but finally dipped my toes
in and tried C# a month ago... While the language as a whole is a bit verbose,
LINQ is incredible, and the breadth of the standard library is awesome.

------
4ad

        Go is so close to C. Wouldn’t it be great if there was a program that could take C code and turn it into Go code?
        
        There are few attempts to do that:
        
        https://github.com/rsc/c2go
        https://github.com/elliotchance/c2go
        https://github.com/cznic/ccgo
        elliotchance/c2go seems to be the most promising.
        
        I didn’t try any of them as neither seems to be usable yet.
    

Actually, we used github.com/rsc/c2go to port our Go compilers and linkers
from C to Go. It was 100% mechanical translation. No manual steps needed to
achieve correctness.

github.com/cznic/ccgo was used to port sqlite to Go. It passes all the (very
comprehensive) sqlite test suite.

They work very well. The code produced is not very idiomatic Go, but it's not
some monstrous impenetrable computer generated code either. It's quite similar
to the original C code and it's readable and refactorable enough. After we
converted the compiler from C to Go, we spent a lot of time to make the code
more idiomatic.

~~~
WaltPurvis
>github.com/cznic/ccgo was used to port sqlite to Go.

Where is the result of this? Is it publicly available?

~~~
4ad
Sure:

[https://godoc.org/github.com/cznic/sqlite](https://godoc.org/github.com/cznic/sqlite)

[https://github.com/cznic/sqlite](https://github.com/cznic/sqlite)

------
Arnavion
>`a | b` can be written as: `if !a && b { a = true }`

`a || b` ...

The repository _does_ have multiple cases of `a || b` and none of the `a =
true` kind, so perhaps the author realized it after writing this blog post.

~~~
thetic
This one tripped me up too. I'm guessing he meant `a |= b`.

~~~
Arnavion
Of course he meant that. My point was that `if !a && b { a = true; }` is a
silly way to write `a = a || b;`

------
leastangle
> As far as I can tell you can’t step through tests in the debugger

Maybe I am missing something, but that is not correct. You can debug tests the
same way as you debug any other code. Even works with the mentioned/used Go
extension for VS Code.

~~~
kjksf
It's quite possible that it's just my laziness in figuring out how to do it.

All I know is that hitting 'F5' in VSCode builds the binary and runs it under
the debugger.

How would I debug the equivalent of `go test` in VSCode?

~~~
devuo
I have no idea in VSCode, but with JetBrains Gogland, debugging tests is
stupidly easy. Simply add the breakpoint where you want it, left click on the
play button in the line of the test declaration, click debug in the contextual
menu, and off you go.

~~~
ice109
too bad sometimes it doesn't resolve pointers correctly

------
mkup
There's a C++ library for Win32 (and other platforms) GUI programming with
built-in layout engine, wxWidgets. It's a bit old, but works quite good, large
DPI aware etc. Unlike Qt, it aims to be slim, provides native look and feel
for all controls on all platforms, and avoids creating its own leaky
abstractions. Necessary workarounds for old versions of Windows are included
too.

Probably it would be easier to create Go language binding for wxWidgets rather
than reimplementing all that stuff from scratch. wxWidgets already has Python,
Perl and Ruby bindings, and besides Windows supports Mac (Carbon and Cocoa)
and Linux (GTK, X11 and OpenMotif).

~~~
jeremyjh
There are already wrapper libraries in Go for it. I'd say more relevant to the
article is the fact that wxBoxSizer wxFlexGridSizer are reportedly similar in
capability to flexbox.

------
fithisux
My only problem with porting from A to B is how to keep B updated when A
changes. Manual step destroys it all.

------
j_s
Sweet, Windows GUI in Go! Glad I put this off this long...

PS. That evergreen/un-dated content tho!

------
kristianp
Looks like they're using walk and win for the gui.

[https://github.com/kjk/walk](https://github.com/kjk/walk)
[https://github.com/kjk/win](https://github.com/kjk/win)

------
nv-vn
Not naming it Yogo was a missed opportunity.

------
Sembiance
Today I learned that Go does not support the ternary operator. that's sad :(

~~~
Twirrim
Gah.. I hate the ternary operator.

Not that it's necessarily a bad thing in and of itself, but every time I've
come across it in code, I've ultimately had to yank it out because I've needed
to support an additional possibility. I don't get what value it really
supplies, and it seems like people are really fond of using it in the wrong
places.

~~~
userbinator
_I don 't get what value it really supplies, and it seems like people are
really fond of using it in the wrong places._

It's a conditional _expression_ , not a statement, and particularly helps
simplify things like

    
    
        if(foo)
            someVeryVeryLongExpressionEvaluatingToAnLvalue = someShortRvalue;
        else
            someVeryVeryLongExpressionEvaluatingToAnLvalue = otherShortRvalue
    

into

    
    
        someVeryVeryLongExpressionEvaluatingToAnLvalue =
            foo ? someShortRvalue : otherShortRvalue;
    

I suppose to really "get" what the ternary is useful for, you have to have
some experience with a more functional programming language, focusing on the
flow of the data itself. There, multiply-nested ternaries are really _the_
norm for what you'd otherwise call "control flow" in non-functional languages,
and structures like this are common:

    
    
       value = isAtrue ? A_value :
               isBtrue ? B_value :
               isCtrue ? C_value :
                         D_value ;
    

(Does _not_ work in PHP, but every other language with a ternary will
interpret that as a compact alternative to the far more cumbersome if/else ---
especially if coding standards dictate braces on their own line.)

~~~
skocznymroczny
I don't like the ternary operator ?, because it's not obvious:

xyz = foo ? bar : baz;

What does it mean? Which is the condition? which is the true, which is the
false value? It's not obvious.

In Python it is much more clearer:

xyz = bar if foo else baz

~~~
bshimmin
I honestly struggle to understand how a traditional ternary like this isn't
obvious. The bit before the question mark is the condition (er, like a
question, which ends with a question mark), then the other two bits are for
true and false in the order you would expect.

I will freely admit I try and avoid nested ternaries, which I personally find
hard to read.

