36 comments

[ 3.0 ms ] story [ 96.3 ms ] thread
See also 'The Pervert's Guide to Computer Programming Languages', specifically the "Fetishistic Languages" part:

https://youtu.be/mZyvIHYn2zk?t=2179

You queued it to a very inauspicious place, because of all of the examples in the talk (many of which are quite good) the elixir example is not accurate for the elixir community (in 2020, anyways)
I get he’s saying it has its place as a learning tool, but this is one reason I haven’t looked to seriously at some languages. For example, F# is a “functional language”, but as best I can tell I can do very similar with C# lambdas. To my (admittedly biased) view, F# is the extremist language and C# the middle-road.
Most of the time choosing a language is like a choosing the color or a trim of the same car. It is so boring.
Usually different languages Are tied to different platforms so this isn't really anagolous.
Indeed. You have to pick a 4x4 or motorbike or limousine .. often before you know where you're going.
I'd think a language tied to a platform only can be considered if you want your product to be tied to such platform.
You haven’t tried a wide variety of languages then. I have found the language chosen massively shifts what is possible to write and what is convenient to write.
Reducing F# or functional programming to lambdas is a bit of a stretch. I don't know F# very well but I understand it is very close to OCaml which I know quite well. F# also has algebraic data types, match, type inference, static type checking, etc. I don't know if C# supports all this, but if it does its probably thanks to the existence of F# on the same .NET platform :).
> algebraic data types, match, type inference, static type checking

Of those, C# only has static type checking. AFAIK C# does have some limited type inference (when using LINQ), but it’s nowhere near as powerful and ubiquitous as F#, where the following is completely valid:

  let Add a b = a + b
and it will be inferred as:

  let Add (a:int) (b:int) : int = a + b
This also works in more complicated cases like when you’re accessing a property on a record, for instance.
I think the latest C# also has match (a pattern matching overload of the switch keyword).
When you get anything close to abstracting syntax, C# lambdas start to require more boilerplate than the concrete syntax. Any advanced functional structure is completely not available.
Indeed, the middle ground depends on your perspective. In my view F# is actually the middle ground between pure functional programming and traditional OOP!

F# is much more than just C# with lambdas btw. If you want to write .net code in a functional style then F# is easily worth the time investment to learn.

Just a counterexample: partial function application.

    let add x y = x + y
    let f = add 2
Boom, now `f 4` evaluates to 6. I reckon that doing the same with C# would require a lot of boilerplate.

(And I know I could have said `let f = (+) 2`, I just wanted to spell it out for those unfamiliar with F#)

Wait, I'm missing something here, because it seems that C# would be the extremist language. It even fits the pithy little saying in the article:

    Classes are awesome. What if we made a PL where everything was a class?
I mean, you can use lambdas, but last time I used C# you could still only use them inside a class definition.*

*Note: I haven't used C# in a while, do you guys have free functions yet? If so, ignore this post, my knowledge is just outdated.

As the first commenter sagely says:

> I agree that extremism in order to learn is a great strategy.

I think it is key to consciously decide when you're learning and when you're doing, and to keep that in mind as you act.

If your goal is to learn, feel free to try bold stuff that might not work. But when your goal is to build, stick to boring stuff that you're confident will work.

This applies at all scales. When you're inventing a programming language, is it a scientific instrument or an engineering tool? When you're adding a feature, it is to understand the users or to deliver value to them? When you're changing the signature of a function, is it an experiment or an improvement?

Agreed. I've been shipping software for over 30 years.

Shipping can be quite "boring."

For example, I am about halfway through a social media app (90% of the way, if we include the backend).

The backend was written in PHP. I decided to do that, because it was an "all-purpose" open-source system, designed for low-budget orgs.

Also, I was already an experienced PHP programmer, and PHP is just fine as a server stack. It's not crazy good, but it works great.

The frontend is being written in Swift, which some companies might consider "edgy," but I'm using traditional UIKit, and storyboarding, which many folks would consider "clunky" (I'm supposed to use SwiftUI).

The thing is, is that SwiftUI is still trying on outfits, and the app is going to be very complex. I am not yet convinced that SwiftUI is "ripe" enough to do an app with the complexity I need.

That said, I want to learn SwiftUI this year, and explore its edges.

I don’t think it applies at all stages (example: spacex vertical landing).
IMO we can and should take measured risks when shipping too. You can only learn so much in fake environments.

You just have to take measured risks, controlling the blast radius as appropriate in your context. But we have to be able to make progress as an industry, and that means taking risks when building real stuff.

This hits home. Great way to learn on a little risk free side project, where you can pivot on a whim. This is how I like to learn.

Unfortunately at work we have SCRUM teams that practice this methodology religiously, but not on side projects. One team spent two months building a buggy functional wrapper around gRPC. When asked why- "We did it because it wasn't functional". The result is gobs of wasted cycles building overly complicated and abstracted garbage, and then further amortizing that over time with ongoing escalations.

I'm not sure how to help them gravitate away from shiny things to focus more on outcomes (simplicity, reliability, speed of delivery, meeting needs and creating value, etc..)

(comment deleted)
Basically the advice is "when learning to use a hammer, see everything as a nail. Nail everything, and use no other tools."

IMHO terrible advice.

Hum... There's no better way to know how a screw behaves when hammed in than by taking one and hamming it somewhere.

As somebody already posted in another comment, just be very clear on what you want to achieve. I'd also add that you must be very sure you can throw it all away afterwards.

That’s not a fair representation of the advice. Using the metaphor, it’s more like: “when learning to use a hammer, try to use the hammer for things that you don’t see as nails; if you don’t, you may miss that it’s also an excellent tool for prying and some kinds of demolition; if you do, you’ll also learn where it’s ill suited for the task, such as tightening screws.”

It’s excellent advice.

Why terrible tho? Go all out overdo it. Afterwards you won't have such a great urge to press everything i to your ideomes anymore. Better do it in a fun little side project and try it out than doing it in professional projects because you never could before.
I think it's good advice because by doing that, you may discover that your hammer can do more than you think.
If i don't know a few sigils it looks like line noise...

Let's make a PL without sigils...

Now...

What is the 'foo' that i'm reading? is it an $scalar? an @array? is it a %dict? a reference? an object? a función? a keyword?

This is great advice for leveling up your programming skills. Just as with any form of deliberate practice, working at something with some self-enforced handicaps or tight constraints can help build a specific set of skills in a focused way.

Thinking about the evolution of programming languages more broadly, it's interesting to note that a lot of earlier languages were hyper focused on one set of concepts (notably objects in SmallTalk, and pure functions in Haskell but it applies to nearly all of them[0]). More recently though, there's been a move towards more of a mix-and-match and cross-paradigm approach. This can mean serious language bloat (any Scala programmers out there?) but, done well, it can also mean extremely helpful new ways to think about pragmatic code like with Rust's use of algebraic data types (enums).

I wonder if the next generation of programming languages will move even further away from arbitrary constraints as it becomes clearer which paradigms work best for which kinds of problems. For that to be the case, we'd have to become more domain focused and get over our obsessions with finding a universal unifying theory of programming.

[0] - http://wiki.c2.com/?EverythingIsa

Love this article. Applies to many domains, not just programming. Take cooking for example: I've been learning about when to apply certain elements such as herbs, spices, salt, and fats. By trying it everywhere, I learn where certain elements do and do not work.
I love this advice. I used this exact technique when I wanted to improve my digital drawing skills. I forced myself to use just a single "brush" to create a complete drawing every day until I had used every brush. (Desktop computer, Wacom tablet, Sketchbook Pro software.)

30-60 minutes per day for months.

At first I produced some incredible garbage. But after a while, I learned how to take advantage of scaling the brush size, changing the opacity, manipulating color, until I was actually creating pretty cool stuff with the most unlikely tools.

By forcing myself to abuse the tools, I gained skills and insights that probably would have taken me years of "normal" use to acquire. And these skills weren't just a novelty - they could be applied even when I allowed myself to use the right tool (brush) for the right job.

Somebody at Google, Facebook and Apple definitely went with this. "Our company is awesome on internet. What if we do the entire internet in our walled garden?". </sarcasm (more or less)>
Files are awesome. What if we made an OS where everything was a file?

Probably appeared first in ChiOS, circa 1968. "A bit is a file. An ordered collection of files is a a file..." UNIX did a lot of that, and variants on UNIX have taken it way too far. This idea keeps coming around.

Cons cells are awesome. What if we made a PL where everything was made of cons cells?

Lisp 1.5.

Mathematics is awesome. What if we made a PL where everything came from math?

APL, Mathematica.

Arrays are awesome. What if we made a PL where everything was an array?

Matlab.

Enums are awesome. What if we made a PL where everything was an enum?
I like how the author makes an argument for extremism (albeit in a limited context) when, generally in society, common wisdom is that extremism is bad in and of itself.