Hacker News new | ask | show | jobs
by TeMPOraL 1118 days ago
Thanks for putting into words something I've started to feel over time, but never conceptualized clearly.

I agree that closures pass the test - and I too remember when they weren't popular. I also remember what I did before learning about the very idea of first-class functions and closures: I simulated them with some ad-hoc means (like function pointers in C/C++, or passing strings to be eval()-ed in PHP, etc.).

This, I think, is an useful heuristic: the things likely to pass your test are the ones which people who don't have and don't know about them still end up approximating anyway - meaning those things are a natural solutions to some common problems.

I can think of couple other things that pass your test:

- Functions in general. It's the basic organizational primitive in code; working without them is Not Fun.

- Lisp-style macros. There are many problems that would be best solved with some surgical code generation, and having that option built-in into the language makes all the difference. Most languages don't have this type of macros - but that doesn't mean they aren't needed. Having done enough Lisp macrology, I saw that in those other languages I've always been coping. Missing them without knowing what they are.

Hell, look no further than webdev - these days, major frameworks like React, and every other minor library, and even the language evolution itself, all depend on running an external macro processor / code generation tool as part of your build pipeline.

1 comments

A trivial but real one for me is being able to use non-alphanum chars freely in var and fn names. Being able to name a fn 'string->int' or especially something like 'valid?' seems very small but I really miss it in languages with more restrictions on names.
Although less encompassing than what you're talking about, I miss being able to name functions with a "?" at the end when they are a predicate; "isValid?".
That’s what the ‘is’ is for. If you have a ‘?’ character, you don’t need it. But tastes vary. I don’t even like the ‘is’.

1. if isValid() 2. if valid?() 3. if isValid?() 4. if valid()

Number 4 is nicest to my eyes. But I guess if the ‘?’ or ‘is’ (or both) is a promise to the user that the function is a true predicate, then I can see its utility.

'?' / 'is' get more useful with more complex predicate names than just 'valid', and they also help with certain corner cases in English. For example, what does the following code do:

  if(widget.free()) { ... }
Does it 1) check if the widget is "free" (whatever that means in the widget domain), or 2) frees the widget and checks the outcome of that operation?

If I saw something like this while reading code, I'd pause and carefully check what exactly is going on here.

In fact, I was going to write "Option 2) resembles resource management patterns, for example memory management in C", but then I checked and noticed that free() in C does not return a value, so this pattern would not exist with malloc()/free() - in other words, despite doing a bit of C and a lot of C++ in the past two decades, I still tripped over this.

Now compare with:

  if(widget.isFree()) { ... }
  if(widget.free?()) { ... }
Both resolve this ambiguity.

On that note, I'd love some kind of sigil for "asserting" functions - which are similar to checks, but instead of returning true/false, they ensure the argument is in the state described by the function name, or else they throw an exception. It's a pattern I've been using in exception-ful code to cut down on noise. For example:

  // Check if connected; if not, maybe run reconnection
  // logic or attempt some other form of recovery.
  // The only way control proceeds past this line is if
  // the session is connected; if it isn't and can't be,
  // exception is thrown.
  EnsureConnected(session);
   
  if(IsSomething(session, arg1)) {
    // ... some code requiring connected session
  }
  // ... more code requiring connected session
It's not a big deal, but in some cases, that "Ensure" or "Assert" look weird, and I don't like inventing more synonyms for the same pattern.
> Does it 1) check if the widget is "free" (whatever that means in the widget domain), or 2) frees the widget and checks the outcome of that operation?

Just program in Esperanto! So 1) would be "umo.libera()" and 2) be "umo.liberigu()".

I can't believe I still remember the grammar after what, 10 years of complete disuse?

Good points.

I’d avoid overloading a standard library function name like free().

Your request for syntax for assertions reminds me of the ‘guard’ keyword in Swift, which is good for making sure of preconditions.