HNHacker News
TopNewBestAskShowJobs

bitwalker

511 karma · joined May 10, 2013

Senior Compiler Engineer at Miden
submissionscomments
bitwalker··on Functional Imperative Programming with Elixir (2018)
Good points! The time where the `while` loop is actually better is very situational, but when it is a better fit, it is definitely handy to have in your back pocket. But more generally I just think it is useful to know how you can implement language constructs like this in Elixir with nothing more than the primitives it provides, some macro glue, and a bit of creativity :)

A couple things though; one issue with your first example is that you incur a 1s wait for either success or failure conditions, where what you typically want is for only the failure condition to impose that cost. Luckily, you can keep this approach and fix it by removing `Stream.zip(Stream.interval(1_000))` and replacing it with `Stream.intersperse(Stream.interval(1_000))`.

The other problem though is that you end up incurring quite a few additional function calls vs the `while`, since the `while` inlines the predicate and associated machinery. You end up with precisely one function call per iteration, with the ability to exit early on failure or timeout, whereas the function-based form is going to incur potentially several function calls, depending on how the `Stream` is being constructed - if I recall implementation details correctly, your first example would be a minimum of 3 calls per iteration; one for the unfold, one for the interval, and one for the take_while.

Of course, that's all really just optimization, and your `Stream` based solution is perfectly fine in general. The only additional benefit (IMO) to the `while` form, is that it reads very succinctly, and due to most being familiar with imperative constructs like that, they can read it with virtually no effort, where reading the `Stream` form takes some care to understand what you get at each step, and what it produces in the end.

RE: Mutability, I think I mentioned it in the post, but I really didn't want _actual_ mutability, just the appearance of it. So while one could use the process dictionary, or ETS, or even another process, to get something like "real" mutability, that kind of defeats the point ;)

bitwalker··on Functional Imperative Programming with Elixir (2018)
Thanks! I don't write very often, since I don't really know if people get anything out of it, but feedback like this is definitely encouraging :)
bitwalker··on “What Alan Kay Got Wrong About Objects”
I’m not sure I agree. For example, nothing about Erlang makes it unsuitable for a browser environment, it can handle running single threaded, or distributed across workers, where each worker runs its own scheduler. The only limitation is interacting with the DOM, since that must all happen in the main thread, but it is still possible to treat that the same way other blocking I/O is dealt with in the scheduler.

I’m actually working on a compiler/runtime for Erlang for WebAssembly, so I’m maybe more familiar than most with how it works in practice.

bitwalker··on Larry Wall has approved renaming Perl 6 to Raku
Neither Elixir or Erlang have real arrays, unless you want to count tuples. That said, I don’t see how that correlates to scripting, the data structures that are first class in Elixir are very ergonomic and certainly flexible enough to tackle pretty much any task you’d use a scripting language for.
bitwalker··on Unison – A statically-typed purely functional language
Indeed! (Hi Ian!)
bitwalker··on Ten Years of Erlang
> The former is a distributed programming DSL (an awesome one granted)

I mean, that's a completely incorrect characterization of Erlang, regardless of how you feel about the comparison to C#.

Erlang is just as much a general purpose language as C#, it is just a different paradigm, i.e. functional programming rather than (mostly) object-oriented.

> There is 0 Erlang-native GUI libraries

This isn't true at all. There is a tight integration with the wxWidgets framework (in fact, one of Erlang's handiest tools is built with it, Observer). Scenic, as mentioned elsewhere in the comments, is for Elixir (perhaps there is an Erlang-native API for it, not sure), but provides a native framework for OpenGL, and a UI paradigm that meshes nicely with processes and supervision.

Of course, Erlang is not perfectly suited for all environments (e.g. iOS apps), but that is true of essentially all general purpose languages - there are some places where they aren't well suited or have flaky support. I wouldn't build an iOS app in C# either, it makes little sense to use anything other than Swift/Obj-C in that environment. Likewise if I'm primarily building Windows-based apps, I would use C# before I would reach for Erlang. But for backend services, infrastructure, networking, etc., it is extremely well suited, and I think the domains that it can provide a compelling solution for will continue to grow (e.g. embedded).

bitwalker··on Elixir 1.9
I was initially hired at DockYard to work specifically on releases and their eventual integration into core, but I am not a member of the Elixir core team itself :). In any case, that in itself is not really a relevant detail, since José and I talked frequently about the core implementation, so being on the core team wouldn't have changed much there.
bitwalker··on Mazda is purging touchscreens from its vehicles
The whole point is that you are neither reading or writing them, they are read _to_ you, and you dictate messages if you feel the need to reply while driving, but both can be done with hands on the wheel and eyes on the road. I suppose it is up for debate whether just the act of listening or speaking is distracting enough to be considered a bad thing.
bitwalker··on The decline of the family has unleashed an epidemic of loneliness
I don't think the decline of the family is the primary issue today. My own perspective is that the "epidemic of loneliness" has more to do with the prevalance of, and addiction to, social media in its various forms.

It is easier than ever to form and maintain all your relationships, acquaintences, friends, and family, online via social media. You can see what people are up to, even "participate" to some degree via commentary/messaging, and it leaves people feeling like they've done their part in keeping the relationship alive. My observation is that because relationships kept this way are increasingly normalized, people are less interested in getting together in the physical world because it takes a lot more effort, and requires a much more significant investment in time.

On the plus side, it means you can keep relationships alive across great distances, and even during times where life is so busy that you have limited spare time.

But the problem is that forming meaningful relationships becomes an increasingly difficult task, to the point where you can begin to wonder if there is something wrong with you due to not being able to form those relationships. Further, you feel increasingly disconnected and isolated, when you have a lot of skin-deep relationships, but none which are truly meaningful.

I consider myself lucky to have a wonderful wife, and her company is more than enough to sustain me even when nobody else is around; but both of us still feel the isolation when we are unable to get together with friends for too long. We moved away from my home state, and she immigrated from another country, so both of us have left friendships behind, and been trying to form new relationships near where we live. It has been harder than expected, and I think it is in part due to people finding it really easy to blow off getting together in person when there is even the slightest inconvenience, especially knowing that they don't have to actually meet in person to keep the relationship alive.

As a result, my pet peeve these days is when people, when asked why they keep blowing off getting together, say "I've been so busy". For one, it is a meaningless statement, most people are busy, it is just the nature of having to work at least one full-time job and then fit in the other activities you want to do in the time left over. Most people still find time to get together with friends at least once in awhile. Thanks to the perpetual need to post everything on social media, it is usually evident that the "busy" person is not really actually busy, and instead what they really meant was "I've been too busy doing things I value more than our friendship, but am too uncomfortable to tell you that".

I don't know if it is related or not, but in my experience, the detachment derived from social media seems to go hand in hand with avoiding anything that is perceived as unpleasant, such as being honest with someone when it is a hard truth, e.g. "hey, my life is full, I'd like to keep in touch, but I'm not in a position to add new friendships right now".

This probably comes off as a rant against social media, but I'm not really anti-social media, I just think the way we find ourselves using it has real, detrimental effects on human relationships, in a way that we don't really understand and are only really starting to see the impact of.

bitwalker··on Terminus: a configurable terminal emulator for Windows, macOS and Linux
+1 for kitty, it is fast and lightweight and provides all the features I've wanted out of my terminal
bitwalker··on Four Years of Rust
The typical approach here as far as I'm aware is to use a deallocation queue - frees of an object that was allocated on another thread are freed by putting that object in the original thread's deallocation queue. When that thread gets an opportunity, it frees everything in its deallocation queue to reclaim that memory.
bitwalker··on US refuses to ground Boeing 737 Max
Airspeed and angle-of-attack are different measurements, whether the AoA is borked or not would make no difference to airspeed measurements, and vice versa.

Without AoA though, airspeed alone is not enough to determine a stall. If one or both sets of probes are incorrect or inoperable, detection of stall conditions would be unreliable at best, either reporting a stall when there isn't one, or failing to report one that is valid.

As for MCAS, it would likely be able to see that two AoA probes disagree, but would be unable to choose the "correct" probe. A third AoA probe _might_ address that, but I never saw that kind of configuration on aircraft I worked on, and it isn't on the MAX. Regardless though, from what I've read, MCAS only applies gradual nose down trim, so ignoring whether or not MCAS even knows enough to disable itself in abnormal conditions, the pilot/first officer should have more plenty of time to react to it (I believe it was something like 2.5deg of trim every 10s). Either the pilots in these situations are not aware that it is a trim issue, which seems very unlikely, or they are overloaded and don't remember in time to set the stab trim to cutoff which would disable those inputs. Very much still on Boeing in my opinion, but it isn't like the aircraft is just diving into the ground the second MCAS starts nosing down.

bitwalker··on What is the Boeing 737 Max Manoeuvring Characteristics Augmentation System?
They can't agree though - angle of attack and airspeed are two different measurements. Together they can be used to detect a stall condition, but independently are insufficient. Furthermore, if either are incorrect or inoperable, then a stall may be misreported or not reported when it should be.

AoA is really the weak point in my opinion, the probe can get stuck or iced up; they always seemed extremely fragile to me for something so critical. Not to mention, redundancy is limited by the number of probes, of which there are only two on all the aircraft I've worked on, so if they ice up, that's it. IIRC that's what started the chain of events which brought down the Air France fight.

bitwalker··on “No, we’re telling everyone we are using Java”
A bigger problem is this:

- Given a distributed Erlang system with two nodes, where both nodes are running the same release;

- Given the same process (Erlang thread) on both nodes, running the same code (i.e. a GenServer backed by the same module)

- Given a new version of the release is being applied

You can't assume that the two processes will be upgraded at the same time. This means that messages sent between those processes may violate the types expected by one version or the other. Furthermore, in Erlang, any process can send a message to another process, so there is no way to enforce that the data a particular `receive` expression gets will even be a type defined in the code it is running. Furthermore, even on the same node, during an upgrade, some parts of the system are still running old code, while some parts are running new code, so it isn't even specifically about distribution.

There is a whole area of type system research around session types, which are designed for more or less this use case, but from what I've seen, none of them handle the case of arbitrary messages, or the case where system upgrades are being rolled out and old code may receive messages from new code.

I still think there is a place for a type system in Erlang/Elixir, but it would have to deliberately ignore process messaging at the very least, at least until a type theoretic solution is available.

bitwalker··on “No, we’re telling everyone we are using Java”
Ericsson absolutely still uses Erlang [1] - the vast majority, if not all, of the core Erlang/OTP team are employed by Ericsson, and that team is still very much active and constantly improving the language and runtime.

[1] https://www.ericsson.com/en/news/2018/5/erlang-celebrates-20...

bitwalker··on “No, we’re telling everyone we are using Java”
I've been working in both professionally for several years now and talked with many over that time, at conferences and such, and have yet to hear "horror stories", but such stories could definitely be useful as illustrations on how _not_ to build a system in Erlang or Elixir, so you should share examples!

I _have_ seen some projects with pretty terrible code, but that has nothing to do with Erlang/Elixir, and everything to do with the skill level of the team behind the project.

bitwalker··on “No, we’re telling everyone we are using Java”
It is really the BEAM that is most compelling, Elixir is a great language on top of it, but the VM provides tools that simply don't exist in most other languages, if any. Specifically things like runtime tracing with pattern matching, the ability to connect an interactive remote shell to a running system and poke at it using code, ETS/Mnesia, hot upgrades/downgrades, etc.
bitwalker··on Belgian Air Force F-16 destroyed by fire during maintenance
It has to be done from outside the cockpit, but is not unusual as a prerequisite step for a variety of avionics systems tests and repairs (source: I'm an ex-USAF F-16C/D avionics maintainer). They may have had it overridden for a check, or if deliberate, done so prior to entering the cockpit.
bitwalker··on Rails, still?
I commented elsewhere already, but you do need to know _some_ OTP to be productive. But those basics (processes, messaging, supervision) can be learned easily in an afternoon.

In my opinion, OTP is not the reason why the learning curve is steep. If anything, the learning curve is steep for those trying to switch from something like Ruby to a functional programming language for the first time. A language with immutability as the default, no concept of classes or objects (though viewed through the Alan Kay lens, processes could be seen as "true" objects). If it is your first FP language, most of one's object-oriented experience is not going to help, so there is a lot to absorb before you even get to Phoenix or OTP.

bitwalker··on Rails, still?
I think it's disingenuous to say you don't need to learn OTP. You need to learn the basics of it, or you will struggle, because you will be trying to solve problems in a way that doesn't fit with the underlying language and runtime. That said, learning the basics of OTP is super easy, and can be done in an afternoon (spawning processes, sending messages, supervision, understanding what applications are in Erlang/Elixir parlance).

It's like saying you can build a Rails app without understanding classes/objects - sure maybe you could throw something together because the tools are so friendly, but you would get lost pretty quick when trying to do something on your own. Learn those basics up front, and you can get a long way without having to delve into more advanced topics.

bitwalker··on Introduction to Go Modules
Unless you statically link your dependencies, but that comes with its own can of worms.
bitwalker··on News for the tz database
There were already many duplicate abbreviations, so this isn't a new problem, and as you said, is a bad assumption, those systems would likely already be incorrect. I would guess systems using abbreviations like this presumably are using POSIX timezones, which isn't going to be historically correct, but require defining all the information about the abbreviation/zone anyway (i.e. they are basically made up timezones, so it shouldn't matter).
bitwalker··on Confessions of an Unreal Engine 4 engineering firefighter
Was this the Pandemic Studios version of Battlezone (i.e. Battlezone II) or the first version of Battlezone for PC? If you had a hand in either, then I owe you a beer (or whatever you prefer) a bunch of times over because I loved both of those games so much. Endless hours of entertainment!
bitwalker··on Concurrency I can finally understand and write correctly
The other reply mentioned tools and documentation, which are the big differentiators in my opinion, but there are also some language level tools in Elixir which feel more "modern" I guess, the macro system which is on part with Lisp, protocols, a consistent standard library which extends Erlang rather than replacing it (although it does duplicate some things, both because binaries are the default string type in Elixir, and because OTP has a bit of an annoying problem with switching the position of the subject), and some conveniences like pipelines, the `with` construction - basically it produces something which semantically is like Erlang at its core, but how you go about solving problems in it offers a lot more options, which oftentimes result in a lot less code written for the same effect.
bitwalker··on Tail Recursion Tactics: Fibonacci
I prefer to use recursion in a lot of cases in languages with pattern matching in function heads (e.g. Erlang or Elixir), particularly when each "case" deals with the accumulated state differently, which is more often than not.

When you are doing simple maps/filters whatever, then yeah, higher order functions all the way.

bitwalker··on Message Passing and the Actor Model
I would spend some time experimenting with Erlang or Elixir. The thing that really made the actor model "click" for me was how each actor in Erlang is just a process (green thread basically). The only way to communicate between processes/actors is message passing, and the way you end up constructing software is by modeling individual tasks and responsibilities of your application in terms of processes. The way processes are constructed in Erlang/Elixir allow you to pattern match on messages to selectively receive or prioritize messages, and discard others. A process can be written in such a way that it changes from one role to another just by being sent a message, or from one state to another (in the case of finite state machines and the like).

A typical example of how it gets applied might be a web server, where each HTTP request is handled by its own process, and potentially delegating multiple tasks concurrently to other processes in the background which handle queuing and executing work associated with that request. You might have pipelines of processes, each responsible for some specific task/transformation before handing off work to the next stage in the pipeline. On top of that Erlang/Elixir provide supervision, where components of the system are started/monitored by a special process type called a supervisor, which will restart its children when failure occurs, and if a set of conditions fail, will itself be restarted by its parent supervisor. So your application ends up structured as a tree of supervisors and worker processes, where components of the application are branches of the tree, and can be isolated from the failure of other components.

Hopefully that helps give you an idea of how the model plays out in practice. I would definitely recommend playing around with either Erlang or Elixir, they are a lot of fun, and it really changes the way you think - at least it did for me.

bitwalker··on Études for Elixir
There has been a huge amount of change in the language since 0.9, so this is probably wildly out of date.
bitwalker··on Functional Programming Jargon
I bought a physical copy of this recently, it's been great so far, certainly the best introduction to the topic I've read.
bitwalker··on Clojure vs. The Static Typing World
For me, fleshing out as much of the types/taxonomy as I can is one of the first things I do before coding towards a solution. Even if the first stab is rough, adjusting the types as knowledge of the domain grows has never been a point of friction for me - most of those changes are incremental, and having the compiler remind me the places I need to update (such as pattern matches) means I don't have to put any mental effort towards that. Even when the changes are significant, I'm still going to have to make basically all the same changes I would have had to make with no type system too. Having the compiler help me out during quick iteration means I can feel comfortable that I'm not forgetting to update areas of the code impacted by changes - when I get to where I want to be, I can be fairly sure I didn't miss anything. That comfort is something I value a lot more highly these days.
bitwalker··on The Ergonomics of Type Checking (2016)
What prevents you from writing the exact same exceptional code in a static system? I'm not sure I understand your point.
← PreviousPage 4 of 7Next →