Hacker News new | ask | show | jobs
by barrkel 1339 days ago
Concepts can often be simulated in many languages, but only clumsily, and the lack of ergonomic affordances in syntax, control flow and type systems can lead one to believe that a different paradigm doesn't work very well - it can be hard to see the wood for the trees.

It's hard to write a declarative querying library in C. SQL is not an ideal language, but as a way of expressing intent rather than a physical query plan, it's a long way away from C.

It's hard to appreciate the power of interactive debugger REPLs like binding.pry or JS's debugger without experiencing them. A C++ debugger, even a Java debugger, is a pale imitation, and it's not easy to simulate the experience without building a dynamic language inside the static language.

If all you've ever known is statically typed languages, you can suffer from a myopic parochialism with respect to dynamic typing. IMO the most popular statically typed languages only work well because they have runtime polymorphism holes in their type systems. More powerful statically typed programming languages tend to grow ever more esoteric typing constructs to enable static types to follow dynamic control and data flow - there's an inherent tension there and if language complexity isn't carefully managed, it becomes harder to express intent and error messages get more vague and cryptic.

Algebraic data types and pattern matching tends to be under-appreciated if one is schooled in object-oriented languages. Object orientation has a big hammer for switching control flow based on data values, dynamic dispatch, and architectures tend to leverage dynamic dispatch where they would be much better off with switch statements. If the set of variants is known up front, you're probably much better off with sum types and pattern matching than with interfaces, abstract classes and virtual methods.

1 comments

It's interesting you bring up REPLs. I never in 20 years working have ever worked with one. I switched jobs and a few people are coco in love with them.

This probably more than anything else comes down the programmer style. I had to use Jupiter notebook to help my wife learn programming Python and it was horrific. I could never imagine that real work was done in this way, but I know many good programmers that swear by it. I suppose that when I need something like a REPL, I tend to use my debugger instead.

Well, there you go. Jupyter isn't very much like binding.pry, because it lacks the debugger-ness.

REPLs without the debugger bit aren't nearly as good. That's why I mentioned debugger for JS and binding.pry (implicitly, for Ruby).

binding.pry pops you into a terminal REPL with the local binding in scope, just like the eval function of your debugger; except you can start writing loops, define new variables, and more rarely, new functions, right there.

When writing code with a test-first model, you set up the data fixture then pop a binding.pry in the implementation, right where you expect to start implementing it, and run the test. You can then implement the logic in the middle of the test execution - in the middle of your debugger session - and because the REPL is so expressive, you can do a lot. You then copy & paste out those lines and save them in the implementation logic, and shuffle the binding.pry on to the next spot.

Or in a hobby project, you can fly by the seat of your pants, and write code live on the server. There's a remote version of Pry if multiple workers sharing a terminal start fighting each other to own keystrokes.

I agree with your sentiment about REPL's, but there are two use cases where they're very useful.

1. When you need to explore behavior.

For example, C# has slicing syntax now. MyString[..15]. What happens when the string is only 8 characters long? Lets hit the REPL and find out.

2. Poking at systems using the same code as the rest of the codebase. For example, RoR. Being able to load up the RoR framework and poke at the ActiveRecord objects can be hugely helpful for tracking down an issue.