inky has a blog inky writes about stuff

January 2, 2016

Advent of Code pt 1

Filed under: Uncategorized — Tags: , , — inky @ 3:19 pm

So I spent most of December working on Advent of Code. I thought I’d go with the thing somebody suggested and solve each day in a different language, which turned out to be pretty fun. You can see my solutions on github but I figured I’d write a little thing up too. This is mostly about the languages but also a bit about the questions themselves, so it has a few spoilers. If you do want to solve this yourself you might want to hold off on reading it.

Day 1
Language: C
Prior experience: Some
Development time: <1 hour
Good ol’ C. Nuthin’ beats that. I decided to start off with C and C++ for the first two days, because I figured that the later problems would be more difficult (somewhat true), and it’d be better to save the more flexible languages for later (probably not true, given that when I had difficulty later, the issue tended to be that the solutions were too slow). This one also looked like a good match for C since the input wasn’t too complicated to parse. I’ll get into this more later, but part of my personal rules here is that I should be able to parse somebody else’s input without changing the code, which means the code has to be able to parse the input file, which means I had to look up the correct way to read a file in C.

Anyway, the only real surprise here is how little professional experience it turns out I have with C. I think of it as a language I know reasonably well, but I can only think of one time I was paid money to work on it, and that was as part of a JNI library for a java program. I guess it was in large part a school thing, since a bunch of classes assumed C or C++ (even though the intro class was in Ada. Damn, I should have done one in Ada), and then later there’s always times when you have to get a tool to work (plus I had a lot of formative years in school spent reading dikumud source code).

Day 2
Language: C++
Prior experience: Some
Development time: <1 hour
This one I’ve been paid for, since the original version of Metacrawler was a C++ apache module. In terms of raw experience, I am pretty sure I have more hours in C++ than in C, but in terms of percent of language and ecosystem known, it’s no contest. C++ is way more complicated and it’s only gotten moreso since I learned it. To be fair, C has more complexities than it seems like at first glance – if you care about performance and 5-nines correctness there’s a lot to learn about compiler optimizations and exactly what behavior is undefined, but C++ has all that plus the language and libraries themselves are complicated.

The main thing I remember about C++ is that we had some performance issues in the aforementioned apache module, and did a bunch of profiling stuff, and ended up deciding the issue was we were copying strings too much. So somebody on my team rewrote strcpy in inline assembly, and it was all very badass, but then it turned out this didn’t actually improve performance at all. In fact, it turned out the real issue was we were passing around string objects by value everywhere, and when we changed all the method signatures to pass references around instead, that pretty much fixed the problem. There is some moral here about premature optimization, but it’s also weird in retrospect that the languages that were standard new programmer languages when I was in school are now, by comparison, experts-only languages.

Day 3
Language: Bash
Prior experience: Some
Development time: <1 hour

Every time I have to work on a shell script that does something meaningful, I think “I bet it would be faster to rewrite this in perl/python/ruby” and I never do and I always regret it. The thing about a unix worse-is-better kind of philosophy is that it promotes getting little projects working and then growing them organically until they solve the whole problem. This applies to both bash scripts and bash as a programming language, and it’s got the same issue in both cases – you end up forcing the original design into crazy forms it was clearly never meant to take, and each successive thing just gets more unwieldy. Or to put it another way, I had a problem with the script that I couldn’t understand (basically, why I’m having to echo the positions inside the loop instead of outside), and two weeks later I overheard somebody at work explaining that loops create a new scope inside, and I said “oh” and “well, that’s dumb”.

Day 4
Language: Postgres SQL
Prior experience: None (but a lot for SQL in general)
Development time: <1 hour

I knew when I set out to start this that some of the languages I was thinking about would have issues reading in input from the command line, so when I saw this problem, I decided the modification of the rule was if it links to a separate page with the input, then you have to parse that as a file, but if they give an input string on the problem page, you can hardcode that into your program. Then having decided that, I figured I could do this one in Postgres. I’ve never used Postgres before but it’s one of those things that everyone says is awesome. Given that, and given that it’s nevertheless not the standard free database server, I wasn’t entirely surprised to see that setup was kind of a pain in the ass. I think I spent about half of the development time on this problem getting access to the database to do anything, and the other half knocking it out. Anyway, this wasn’t really a showcase for its talents, but Postgres is cool.

Day 5
Language: Go
Prior experience: One personal project
Development time: 1 hour

I am a perpetual late adopter, but I try to stay on top of things in my field, so there are usually long periods when I am aware of some particular technology but refusing to have anything to do with it. I recognize this is mostly an emotional reaction to other people looking like they are having fun and not a rational reaction due to the fun being on my lawn or something, so I try to poke at these feelings occasionally to see how they’re doing. Which is a long way of saying that Go still feels irritating and ugly, but it is totally true that with this project and the other thing I’ve done in Go, I was able to get shit done with a minimum of bumps.

Day 6
Language: Ruby
Prior experience: A bunch
Development time: <1 hour

Like I alluded to in the first question, there’s sort of a tricky strategy thing here in terms of deciding what language to do when. Ideally you save specialized languages for things they’re good at, difficult-to-use languages for easy problems, and easy-to-use languages to fill in any gaps, but if you’re going through one problem at a time, you don’t really have all the info you need to make these decisions (and when you’re looking at part 1 you don’t necessarily know if part 2 is going to be radically different make you regret your choice). Also, it turns out sometimes I wanted a break from learning new stuff or only had limited time to work on the problems and wanted to make some progress.

Most tech companies I’ve worked at have a setup where the main code is one language and has pretty strict rules and practices over how you modify it and add things to it, and then there is another pile of “other glue stuff” that makes the whole system work (like running the builds, deploying the code to production, monitoring, scheduled jobs to do various cleanup or logging things, etc), and it is basically the wild west in there and people write in whatever language and follow whatever practices they feel like. Things were a little more disciplined than usual at zulily, where we standardized on ruby fairly early on, and people were generally pretty good about following standard practices, but I still learned it mostly as a glue language, and we had a few growing pains when some of the glue scripts got big enough they should really be maintained with best practices instead of whatever-works practices.

Anyway, the only other comment I have here is I am sorry I was too lazy to write a single program that would handle both part 1 and part 2 and instead copied my part 1 solution to a new file and modified it. … Ok, fixed, I feel better now.

Day 7
Language: Lua
Prior experience: None
Development time: <1 hour

I’ve heard a bunch of stuff about Lua and never used it, so this seemed like a good opportunity. Having done the problem with it, I would say Lua seems nice enough but there’s no particular reason to prefer it over Python or something. I don’t think that’s really the value proposition, though – my impression is the big use case is using it as an embedded scripting engine vs C, and there it clearly is a win. But there’s nothing in particular about Lua that makes it useful for that, as far as I know, except that it’s easy to embed the interpreter. Which is interesting, since it reinforces that popularity is often a right-time-right-place thing and not really objectively true about a language.

Two quick additional comments:
– In Lua, what’s the difference between package.function(obj, args) and obj:function(args)? I thought they were interchangeable, but the latter appears to only work some of the time.
– In the full input, it’s possible for a variable to be used before it’s defined, but in the sample problem, that isn’t the case. Similarly, the full input allows definitions of the form “x -> y”, when the sample only includes “x AND z -> y” and “3 -> y”. This seems like a bad decision on the problem creator’s part – I don’t think the sample problem has to demonstrate all the subtleties of the full problem, but this seems like a pretty major requirement to omit.

Day 8
Language: Java
Prior experience: Lots
Development time: <1 hour

Welp, Java. This is my day job and has been for the past while. I think the main evidence of that here is slightly more error-checking. Also I guess that I’m aware that java 8 has a bunch of functional constructs. I wonder if anyone solving this with Perl or Ruby used eval to do the initial decode? That’s the kind of cleverness where it just bites you on part 2, though.

Day 9
Language: Clojure
Prior experience: A little
Development time: <1 hour

We use Riemann at work and I’ve wrestled with its config (which is in Clojure), and that’s the extent of my previous experience. The thing about macro-heavy languages like Clojure, though, is that how easy it is to modify a piece of code depends in large part on the macros that the original authors used. With, say, Java, if you see a piece of code, even if you don’t understand it you can break it down into atoms and rearrange those atoms. In Clojure, it’s possible that atoms are only viable within their enclosing macro, and if you try to rearrange them or cram more in, the whole thing dies mysteriously. So although I was griping about Clojure at work, when I was solving this problem things were really smooth and fun.

That said, getting the development environment going is kind of sucky – this seems to be one of those ecosystems with a whole custom build environment they expect you to use, and they expect you to structure your directory in a certain way, and so on. But like with Go, if you just give in and do it the way they want, stuff works out fairly smoothly. It’s also kind of slow to start the script (unsurprising for a JVM language) and error stack traces are garbage after the first couple lines (again, not too surprising for a JVM language, but since they’re using a custom runtime it seems like they could have dealt with that). But a good REPL makes up for a multitude of these kind of sins, and in general stuff was good.

I think that’s enough discussion for now. Days 10+ in a later post.

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress