1. 30

Tailwind & consort kinda target something the author seems to forget: many web developers of today are deeply entrenched in “component based frameworks” that kinda prevent such repeat of “atomic css snippets” since, well, you develop a “component” that get repeated as needed.

Classic class based CSS already do this, ofc, but only for CSS + HTML, when you try to bring this component/class system to Javascript, you often ends up in something like React or Vue or idk what’s trendy today.

And then you have 2 competing “components” systems : CSS classes, and “JS components”.

Tailwind kinda allow you to merge them again, reducing overhead when having to work with those JS systems.

1. 6

I personally prefer the CSS Modules approach to solve this problem, rather than bringing in a whole framework like Tailwind. CSS Modules give you the isolation of components but don’t force you to leave CSS itself behind, and when compiled correctly can result in a much smaller CSS payload than something hand-written. Sure, you lose the descriptive and semantically-relevant class names, but if you’re building your whole app with components, you really don’t need them.

That said, if I didn’t use something like React, or I just needed CSS that followed a similar modular approach, I guess I would reach for Tailwind. But realistically, CSS is so lovely these days that you really don’t need much of a framework at all.

1. 3

I find tailwind much easier to use than css modules when you stick to the defaults.

1. 3

CSS Modules is an abstraction at a lower level than Tailwind. The former can do everything Tailwind can do in terms of the end result. The latter provides really nice defaults/design tokens/opinions.

1. 2

CSS Modules is an abstraction at a lower level than Tailwind.

Definitely, and that’s why I prefer it. The way I normally organize my applications is by using components, so I don’t really need a whole system for keeping all the styles in order. Ensuring that styles don’t conflict with one another when defined in different components is enough for me. But if I was doing something with just HTML and I didn’t have the power of a component-driven web framework, I probably would try out Tailwind or something like it.

1. 10

I have mixed feelings about Tailwind.

On one hand, I love it and use it in all my personal projects. I’m so productive with it, and it’s a real pleasure to use it.

On the other hand, I will probably never suggest using it in a professional project. It’s too hard to defend it, and probably not worth the debate time.

1. 10

On the other hand, I will probably never suggest using it in a professional project. It’s too hard to defend it, and probably not worth the debate time.

We started using it at work, and people that aren’t particularly front end developers end up loving it because of its productivity. That alone is worth it for the business case.

1. 3

Yes agreed. I have been using it in my LiveView app. But, when I explain it to my friend who is a front end developer he always just says, “but you can do all that with regular css and JavaScript (in relation to LiveView)”. And all I think is, “yes, but I don’t want to.”

1. 1

I hear you. I use it everywhere. I can’t suggest or even recommend it in a professional project—too many pieces of the puzzle for coherent UI are missing: the string-based nature of a styling system based entirely on classNames is hard to override in component trees and difficult to make type-safe

Chakra-UI is pretty good and pretty similar to Tailwind at least as far as design tokens go, however I could not recommend Chakra because of their willingness to break compatibility with React 17 at the drop of a hat, with no warning or deprecation strategy, while React 18 was barely out of the oven.

In my personal projects, my current approach is to build basic components with React-ARIA headless component library and styling them with Tailwind. It is really nice.

1. 1

I use the style attribute in my personal projects. For me, Tailwind does basically the same but with yet another syntax. If it gets more complex than what “style” can handle, it deserves a class name.

1. 20

I long left web development. Funny to see that this Tailwind thing seems to rediscover approaches we already overcame 10-20 years ago in web development when we went from hard-coded styles to CSS classes. And now Tailwind goes a step backwards and uses almost-hardcoded styles again disguised as CSS classes.

I also love this quote, which according to the article comes from Tailwind:

You have to think up class names all the time — nothing will slow you down or drain your energy like coming up with a class name for something that doesn’t deserve to be named.

Yeah, naming is hard, let’s stop naming things so nobody who reads the code later understands our intentions :)

1. 10

Yeah, naming is hard, let’s stop naming things so nobody who reads the code later understands our intentions :)

This is a straw man of the argument, which is not that you should avoid all names, but that you should avoid names when they aren’t needed. It is the difference between (part of) McIlroy’s famous UNIX 1-liner:

tr A-Z a-z |
sort |
uniq -c |
sort -rn |
sed \${1}q


and something like this (pseudocode):

lowercased = lowercase(input)
sorted = sort(lowercased)
counts = uniq_counts(sorted)
sorted_down_by_count = sortByCount(counts)
topN = topN(sorted_down_by_count, n)


The only thing we care about naming here is the final result: “the top n most frequent words”. Naming the intermediary calculations within this context is just noise, and makes the code less readable, not more.

1. 9

The only thing we care about naming here is the final result: “the top n most frequent words”. Naming the intermediary calculations within this context is just noise, and makes the code less readable, not more.

Someday, in one, two, twenty years, somebody will go through that code to debug a problem with locale-aware sorting and they will thank you for having named the intermediate steps. Or they will curse you having named only the result.

1. 5

they will thank you for having named the intermediate steps

They won’t, because the intermediary names provide no new information.

1. 9

the intermediary names provide no new information.

I would agree with this if the intermediate commands used descriptive long options, like sort --reverse --numeric-sort. In that case, yeah, sorted_down_by_count doesn’t add much. But compared to sort -rn and having to guess what those short options do or needing to peek at the manpage, i’d take a meaningful name like sorted_down_by_count any day.

Short options are nice for exploration on the command-line. But for actual scripts written onto files that other people might need to read, the descriptive naming of long options should always be preferred IMO.

1. 4

Yes I agree with this point. I was just using the McIlroy command verbatim. But long options for scripts all the way.

2. 3

They absolutely do provide new information

Firstly, you don’t have to mentally translate tr A-Z a-z into ‘start by lowercasing the input’ every time you read the code: you directly read ‘lowercase the input’. So the name provides information that is new when you haven’t mentally performed the translation step yet. Which you then don’t have to, because you already have the name.

Secondly, the name communicates the intent: the ‘sorted’ variable is intended to hold a sorted list. If some refactoring or other code shuffle results in that variable being used before ‘sort’ is called, that’s a clear red flag to the reader that something went wrong. So the name provides additional information that the first version does not have at all. You could use documentation/comments instead of names, but not the plain McIlroy version.

I’ll take the second version over the first one for anything that isn’t a throwaway command I construct just to get something done. I’m not a shell and I don’t like being forced to play one.

1. 4

I used to think like this too, and the argument sounds reasonable, but it leads to an overly verbose style of programming which hinders readability for anyone fluent in the language.

The only situation where the argument holds water is if you expect your maintainers to be unfamiliar or barely familiar with the language. Sometimes this does happen, and turning your code into a mini language tutorial can be appropriate then.

Generally, there are two kinds of errors you can make (in code or prose): you can under-explain, or you can over-explain. It seems to me the position you are arguing assumes that over-explaining is not really an error, or is only a minor one. But this is not the case. Habitual over-explaining wastes a lot of time and greatly dampens the efficiency of communication. You want to get it just right.

Firstly, you don’t have to mentally translate tr A-Z a-z I’m not a shell and I don’t like being forced to play one.

Maybe you aren’t that familiar with bash? Because if you are, it is faster to read the original version. You immediately recognize the familiar names and what they mean.

In fact, the new names introduce new cognitive load, because I must now load up the bespoke lexicon a random programmer into short term memory, mapping between the new terms and their definitions, which I already knew. And no matter how good you are at naming, your “self explanatory” names will never be as good as the terms someone already knows by heart.

1. 2

I used to think like this too, and the argument sounds reasonable, but it leads to an overly verbose style of programming which hinders readability for anyone fluent in the language.

This sentiment is often stated, but I don’t think it’s true.

People read/consume entire words at a time. For example, “–reverse” may be more verbose than “-r”, but it requires the same cognitive effort for experienced veterans. (And, obviously, a lot more cognitive effort for newbies.)

This is why APL isn’t popular, and it’s also why glyph-based written languages are, in my opinion, objectively inferior.

1. 3

This is why APL isn’t popular, and it’s also why glyph-based written languages are, in my opinion, objectively inferior.

As a counterpoint, and one of the best demonstrations of what I’m arguing, I encourage you to see whether the source or rendered output of Latex is easier for you to read:

https://www.mathjax.org/#demo

In the case of APL, the confounding variable is that acquiring fluency takes a very long time. But as someone fluent in J, and somewhat familiar with APL, I can attest that it can become quite readable. Aaron Hsu has some good videos on this.

For example, “–reverse” may be more verbose than “-r”,

As I said in my other response, I am in favor of long form flags, but it is a fair question to ask me why, as my argument could imply that short ones are better, so long as they are familiar. I think that, with flags, that so long as they are familiar is just too rarely true – there are too many of them, across too many tools. It’s too hard to make assumptions about familiarity, as opposed to “knowing what sort or tr does”, which is safe to assume of a bash programmer.

There is a lot of judgment involved in getting your “density” right, and I am not arguing to never have intermediate names, far from it. Only that there are plenty of times where doing so is a mistake.

Steve Yegge’s “Portrait of a n00b” is relevant here too:

The question is, what do you do when the two groups (vets and n00bs) need to share code?

I’ve heard (and even made) the argument that you should write for the lowest common denominator of programmers. If you write code that newer programmers can’t understand, then you’re hurting everyone’s productivity and chances for success, or so the argument goes.

However, I can now finally also see things from the veteran point of view. A programmer with a high tolerance for compression is actually hindered by a screenful of storytelling. Why? Because in order to understand a code base you need to be able to pack as much of it as possible into your head. If it’s a complicated algorithm, a veteran programmer wants to see the whole thing on the screen, which means reducing the number of blank lines and inline comments – especially comments that simply reiterate what the code is doing. This is exactly the opposite of what a n00b programmer wants. n00bs want to focus on one statement or expression at a time, moving all the code around it out of view so they can concentrate, fer cryin’ out loud.

1. 2

There is a lot of judgment involved in getting your “density” right

+1

And there’s probably no “one true density” because people are different, even people with the same level of experience (e.g., veterans in computer programming language X).

My real goal here is simply to express the idea that, for example, “–reverse” does not hurt, or slow down, veterans, when reading – their brains gulp down the entire word “reverse” in a single “gulp” - at least, based on what I’ve read about how the human brain works and reads.

1. 1

I encourage you to see whether the source or rendered output of Latex is easier for you to read:

I’d argue that rendering LATeX as glyphs is exactly the same as rendering tr A-Z a-z as lowercase.

If you’re the one who wrote the LATeX and revised it umpteen times, you don’t need to look at the rendered version: you just read the LATeX. The rendered version is for other people to read. And those are not people unfamiliar with LATeX or noobs. It’s also yourself a few months later: then you prefer the glyphs over the LATeX.

1. 1

What you’re missing is that the names typically won’t have the familiarity of well-known mathematical symbols. Sure, in the case of “lowercase”, it does. But the point is that what you typically get is programmers inventing strained words for ideas that don’t map to well-known concepts or anything in the domain – because they’re naming “in between” stuff. The result is a name soup that clouds rather than illuminates.

Another analogy:

The phrase “jump in place” will usefully convey to you a sequence of body positions and the associated motion.

But if I am inventing some weird new dance move that you’ve never seen, which is used only once, then naming it is a waste of time. The demonstration of the move is the most efficient way to communicate it.

2. 1

Because if you are, it is faster to read the original version. You immediately recognize the familiar names and what they mean.

I have my doubts about that, primarily because that’s just not how it works for me.

It only happens like you describe when it’s a piece of code I have recently seen and I already know what it says. Then the pattern tr A-Z a-z is just a place locator for where I am in the code. I don’t need to interpret it, because 9/10 times I don’t care for it. I already know the code is correct, because I’ve recently seen it.

If it’s new code or it’s been a few months, then I need to doublecheck. What happens in my head is tr, OK, A-Z, OK, a-z, OK, we’re lowercasing everything. Every time. It may look like tr A-Z a-z at a glance, but I have to check. It looks a lot like tr a-z A-Z, tr A a, tr AZ az, etc. There are too many small variants that change the meaning. ‘Lowercase’ does not have that problem and has the advantages I described before. The word carries more information than the command.

1. 1

Now the conversation is getting interesting, because I agree with a lot of what you just said but still, for most use cases, prefer the original code.

because that’s just not how it works for me What happens in my head is tr, OK, A-Z, OK, a-z, OK…. ‘Lowercase’ does not have that problem

This is a fair point, but I have two counterpoints:

1. The “checking” you describe is really fast, like a second or less. Granted I have written a lot of bash, but fluency is one of my assumptions.
2. This is perhaps the more important point…. You either:
1. Have to “trust” that the name “lowercase” is correct (just as you’d trust that it’s A-Z a-z and not a-z A-Z when scanning without “checking”)
2. Or have to read the definition anyway.

So in either case, you are choosing your reading mode: “grok gist and trust details” or “verify code” (mode typically depends on use case – eg, if you are debugging you need to verify). If you are “verifying” then the advantage of “lowercase” doesn’t help you (you still have to verify), and if you are “grokking the gist” it also doesn’t help you, because all you care about is that the entire phrase “gets words sorted down by frequency of use”. It only helps when you are unfamiliar enough with the language that, say, it saves you having to read documentation to figure out what a function does.

There’s more…. I chose the example because it was a brief and convenient way to get my point across, but it’s actually not great at demonstrating the worst parts of this style of intermediate naming….

1. The names I chose here are pretty clear, which is “lucky” in a way, because the intermediate objects map to familiar ideas with well-known descriptions. In general, the intermediate objects of your data transformations don’t, and you end up groping to name things that don’t really have “names” (“user input with names validated but addresses still unvalidated”, etc).
2. If you do this anywhere but in a tight local scope (eg, within a small function), the names pollute the larger scope, and a reader must verify that “this is just a temporary name used to describe a step in a data validation” and not “a variable definition that we use again later.”

Again, I’m not against this style when it’s really needed to clarify something confusing… but only against the idea that “all familiar language constructs / short code idioms are inherently more confusing than a named variable.” That view, to me, is almost akin to code like the following, where every line has a redundant comment, which I’m guessing you do not like:

// Gets the array without the first element
const tail = arr.slice(1)

2. 4

Yes, and as the article mentions, CSS lets you avoid names when they’re not needed.

3. 7

if you’re talking about moving away from hard-coded style attributes, this isn’t really a fair comparison at all

There are 2 main differences as I see it

1 - tailwind classes are reusable & concise both as utility classes & via components

2 - you can’t do :hover or :active states among other more complicated css features in style attributes

I think like everything its hard to judge at a distance, need to really try it out to see if its actually problematic.

For me, I used it for a few years & then I stopped but I’m seriously considering coming back because it tends to be better css than I write. I think its really great if you really know css, but for me it was valuable to spend a lot of time in plain css to understand it better.

1. 5

Web development was really different 10-20 years ago. I would argue that Tailwind isn’t really the same approach that we overcame but rather a familiar approach in a different context (component-based frameworks and libraries).

1. 2

!

Yes. I was working on a series of posts about “naming things” this summer, and in the last two posts (https://t-ravis.com/post/doc/the_gizmos_role_in_markup/, https://t-ravis.com/post/doc/the_trouble_with_anonymous_gizmos/) I was bumping up against this and briefly included Tailwind in one of my drafts.

I (temporarily) backed down from mentioning it when I caught a glimpse of truth underlying the separation of concerns part of the argument. I decided to take some time to reflect on whether it’s a logical reaction to (and makes lemonade of) a cluster of ways that HTML+CSS muddle separation of concerns (which I was/am already planning to write about).

1. 5

I am not disagreeing, but I find that a Tailwind stylesheet makes it possible to maintain multiple apps with mostly consistent style. You just pick the components from a library, slap it into a template, tweak with utility classes and call it a day. No need to fiddle with CSS and sync it across the projects. Popular components get included into the library.

It’s super messy and far from ideal, but if you’re on a budget, it makes it possible to get things done with minimal communication overhead while still maintaining a semblance of a corporate identity.

Tailwind is a poor fit for a standalone application / product, I believe. Bootstrap or something more minimal (just for the grid) and custom CSS would work better.

I do hate the gigantic compiler, though. Someone should rewrite it in Rust. :-)

1. 2

I agree, but for the reason that Tailwind doesn’t really have a solution to the problem of overriding styles within component trees, which seems somewhat inevitable when developing applications with a lot of UI.

Not such a big problem for smaller applications. One option is to just pass in a className prop and clobber a component’s default styling. That doesn’t work so well in larger applications—you often want to keep some existing styles but override one or two because of how a component needs to look in a different context.

Maybe more upfront planning and better UI architecture would obviate such a problem. And yet, at the end of the day, sometimes you need to just override that one damned property, submit the PR, and go home.

The article seems way too sure of its answers for me to take it seriously.

1. 4

I use Tailwind* on most of my personal projects. Most of them also happen to be built with React.

I don’t think I would use Tailwind if I wasn’t using it with some kind of component framework. It’s hard to take this article too seriously given that it doesn’t mention how many of its points are obviated by using Tailwind within that context.

*I’ve stopped using Tailwind directly, and now use UnoCSS. UnoCSS allows me to use the Tailwind classnames that I am familiar with, but is faster with a nice set of additional features that help cut down on cruft:

<div class="hover:(bg-gray-400 font-medium) font-(light mono)"/>


transforms to:

<div class="hover:bg-gray-400 hover:font-medium font-light font-mono"/>


Can also declare shortcuts in a configuration file like:

shortcuts: {
'btn': 'py-2 px-4 font-semibold rounded-lg shadow-md',
'btn-green': 'text-white bg-green-500 hover:bg-green-700',
}

1. 1

<div class="hover:(bg-gray-400 font-medium) font-(light mono)"/>

Okay, but what does this div do? Without a semantic tag or a class name, the developer will have no idea why it’s there.

1. 4

Given that the point the parent comment is making is that Tailwind is generally used within the context a component framework, that should be made pretty clear by the name of the component.

Really, I think many of the commenters in this thread could do with reading up on the rationale behind Tailwind. There are some great resources out there, but if you don’t have the problems Tailwind aims to solve, then it’s hard to understand why some people are so passionate about it. I’m sure there are plenty of cases where Tailwind is overkill, but that doesn’t make it an antipattern. If you’re going to criticise something, at least try to understand the motivation behind it.

I was sceptical myself at first. I even tried it early on and it didn’t stick. But I kept running into the same problems, so I determined to give it an honest chance and it has been an absolute joy to work with.

It’s the first time in 15+ years of web development where I haven’t had to constantly think about how to structure things, which class naming convention to use, how to name a ‘container/wrapper/inner’ class, keep track of which CSS is in use and where, or deal with CSS specificity issues.

But the best part, is that it gives you flexibility with limitations. These limitations are what make it trivial to maintain a consistent design system, and it’s up to you do decide where those limitations are. The defaults will take you a long way, but if/when you need to change something (spacing, colours, fonts, anything…), it’s usually just a few lines in the config file.

1. 1

Hopefully starting to code a very simple Pacman in Java with my 10yo son. I’ve tried to start him on Python, but he’s struggling to connect with that, because his ultimate goal is making Minecraft Mods and so he wants to learn Java. Any tips? I’ve never done graphics programming, so could use pointers!

Sunday I’m helping out in the rescue boat at my sailing club, which is hosting a bunch of windsurfers this weekend.

1. 2

Processing is a library and IDE for making graphics, its based on Java but is a nice, curated experience and a lot more beginner friendly. Here’s a bunch of examples https://processing.org/examples/

I don’t know anything about minecraft modding, but since Processing also uses Java, it might be a gentle and fun introduction.

1. 2

Tip 1: Essentially any graphics programming is done through a GPU, the days of sticking pixels directly into a frame buffer are gone. I think there’s Windows API’s that still let you do that, and I’m sure old Java GUI API’s as well, but you may well be happier not dealing with them.

Tip 2: Thus, don’t feel bad at all about using a game library that gives you some higher-level tools. Low-level GPU programming through OpenGL or Vulkan is certainly doable, but IMO is a pretty thankless task when it’s not something you’re fundamentally interested in. (DirectX 11 may be better? I don’t know.) For Java, I recommend libGDX (higher level) or LWJGL (lower level), or maybe there’s a good Java binding for Raylib out there.

1. 1

LibGDX looks just about perfect for what I had in mind, thank you! I wasn’t planning to do anything more complicated than moving around some sprites we load from PNGs.

1. 2

If you haven’t already, you might want to try Godot. It provides a rich set of APIs for defining scenes and lets you focus on the code for the game logic, not the boilerplate for the GUI parts.

2. 1

his ultimate goal is making Minecraft Mods

Awesome! I remember I first got into coding when I was ~12 by modding Minecraft. I thought it was a really great (and fun!) way to learn programming. Learning programming is definitely not a one-size-fits-all kind of thing, but personally I found writing small and silly server-side mods to be a good entry point. At the time, the community made an API called Bukkit for doing this, though I’m not sure if it still exists. There was very little complexity you had to handle within each mod, because it used an event-based system with a huge amount of methods accessible through the API. For the simpler mods, you could just implement one or two functions and have something that compiled and worked, which was very important for a child looking for easy gratification. :)

I would note that the graphics programming involved in making Pacman from scratch, while fun, isn’t really a prerequisite to Minecraft (or most other game) modding. You can directly manipulate the game objects from your code while the already built engine does all of the rendering for you. If your son has the interest, you could encourage him to jump into modding directly – I learned by watching copying some tutorials on youtube and changing bits of the code until I (very) slowly figured out how it worked.

1. 2

I would note that the graphics programming involved in making Pacman from scratch, while fun, isn’t really a prerequisite to Minecraft (or most other game) modding.

Acknowledged. I expect to be doing the lion’s share of the graphics stuff, but I thought Pacman would be a gentler introduction to Java than diving straight into Minecraft. He’s been telling me about how Pacman’s ghosts have different names and behaviours (I hesitate to call them “AIs”, though he does ;-) ) and my idea was we could try to implement those together.

1. 2

At the time, the community made an API called Bukkit for doing this

It still exists, but now basically everyone I know of has their fork-distance-from-Bukkit >1 (s, ps)

If your son has the interest, you could encourage him to jump into modding directly

+1 for this, but the ingame command blocks are also worth mentioning. They’re turing complete, mildly annoying, very easy to get started with and just require the game itself (:

(afterwards you do need some creativity to abuse the mechanisms they give you in order to create more complicated things, but for pacman they should be plenty; you can build a little “screen” out of black concrete, spawn a pig or something and add some buttons with command blocks to teleport the pig around… Later you can make the pig invisible and think of something else to use)

1. 1

Ah, he’s already played with command blocks a fair bit but he’s got his heart set on creating mods in Java.

The mind boggles at creating Pac-Man inside Minecraft. That never occurred to me!

1. 1

congratulations, you’ve recreated CGI-BIN

1. 12

The readme.md mentions its CGI inspiration.

1. 2

Really nicely designed blog. Love it.

1. 2

“None of that taught us HTML and CSS though… It taught us not to understand how the web works, but take any shortcut necessary to get to a certain look and feel.” — What? It did? That’s news to me.

1. 3

Gordon R. Dickson wrote a sci-fi book, published in 1984, called The Final Encyclopedia. It was all knowledge in the world with an AI to search.

I wanted this in real life. Xanadu seems like Ted Nelson wanted it too. Wikipedia is an organized crowd source. The WWW probably contains all the knowledge but you need a search and organization scheme to extract the encyclopedia from the noise.

1. 4

“All the knowledge” in a single container might be possible but it will be hard for people to interact with due to their biases. Wikipedia is a good example of this as it lays bare the difficulty people have with accepting different views - contentious subjects tend to be colonised by a given faction which does its best to eradicate any and all data which negates their position. While it might be theoretically possible to create an AI which can serve as a data steward making sure all points of view are taken into account, it is hard to see how such a machine could survive the wrath of the censor.

1. 3

While it might be theoretically possible to create an AI which can serve as a data steward making sure all points of view are taken into account

I think this view is understandable but naïve, and I can prove it by saying that you are educated stupid for not accepting the four-corner cubic world which wisest human Gene Ray tried to reveal to the world despite the cubeless academia attempting to shut him up at every turn, because all academia is oath-bound to deny cubic reality and preach the Greenwich Fallacy.

Or are you an agent of the Gangster Machine, as revealed by Francis E. Dec? Or are you an X-Soviet Armenian whose grandparents are guilty of genocide against Turks? Hard to tell. With any luck, however, you’ve picked up the thread: Some points of view are not cogent, not rational, and not connected to reality. They only deserve mention in listings of “crazy stuff some people apparently believe” which, no matter how diplomatically you title it, is a category which is always going to be inherently insulting. You have to figure out what a “point of view” is, when it comes to getting all of them represented in an article about some real-world subject, and that kind of bootstrapping problem is an inherent bias in any encyclopedia project.

1. 2

You’re talking fiction, I’m talking facts. The “four-corner cubic world” and the “agent of the Gangster Machine” and more of such are provably false and can be written down as such. Other areas are not so clear and should be open for discussion, a good example here is the issue of climate change. There is a lot of science on this subject which can be used to push a number of views, from “climate change has always occurred and is a natural phenomenon which is unrelated to human activities” to “anthropogenic climate change is boiling the planet”. Have a look at Wikipedia, especially at the discussion pages for subjects related to this issue to see which faction has taken over this area.

1. 7

You’re talking fiction, I’m talking facts.

I guarantee you that some of the things you consider facts are obviously fiction to others, and vice-versa.

The “four-corner cubic world” and the “agent of the Gangster Machine” and more of such are provably false and can be written down as such.

Some people feel the same way about the existence of trans people.

Other areas are not so clear and should be open for discussion, a good example here is the issue of climate change. There is a lot of science on this subject which can be used to push a number of views, from “climate change has always occurred and is a natural phenomenon which is unrelated to human activities” to “anthropogenic climate change is boiling the planet”.

Wrong. Aside from the fact your first “quote” is unrelated to the second, the fact is that AGW is very well-demonstrated and accepted by all serious scientists in the field. The “debate” is funded by people who have some kind of interest in seeing people doubt things we know quite well.

Have a look at Wikipedia, especially at the discussion pages for subjects related to this issue to see which faction has taken over this area.

This is because NPOV is biased towards the scientific consensus, as it should be.

1. 4

This seems like a super interesting article and I’m currently digging into it. At the outset, it isn’t clear to me why there is a space between the name of the function and its arguments.

The article says “Functions are called with a space between the name and parenthesis. This is done to simulate calling functions by juxtaposition, and it’s helpful for calling curried functions.” but that doesn’t actually help me understand anything. What does “calling functions by juxtapostiion” mean, and why is the space helpful for calling curried functions?

1. 3

Hey, glad you find it interesting. The space isn’t required, and you could call it without a space there, but in languages like Haskell where currying is more common than JavaScript, functions are called by “juxtaposition”, where arguments are separated by a space. In JavaScript, calling a function requires parenthesis, and calling curried functions would look like f(x)(y)(z). I added that note there just to clarify the notation because it’s not common to call functions this way, but I think f (x) (y) (z) looks nicer.

I’ll edit it to make it clear that it’s not required and purely there for aesthetic purposes, thank you!

1. 2

It’s not much. In some math texts it is common to write “f x” instead of “f(x)” - that is the juxtaposition which means just “put things next to each other”. That notation is nice, less typing and easy to read, except when there are multiple arguments and function valued expression or other forms of ambiguity. Does f x g y mean f(x,g,y) or f(x)(g (y)) or some other variant. “Currying” just means packing multiple arguments into one as a form of notational simplicity. e.g. f(x,y,z) is f(q) where we’ve done something to stuff x,yz into q or into f itself so add(a,b,c) could be add’(c) where add’(x) = add(a,b,x) or something. Seems pointless in this case.

If you can’t do int x; x = f(0); x = g(x); because your programming language does not have variable assignment, you need to do either g(f(0))
which can become too awkward with complex formulas or have a fancy ; so f(0) ;; g(_)
means “I will avert my eyes while the compiler does an assignment to a temp variable and pretend it didn’t happen”

1. 4

“Currying” just means packing multiple arguments into one as a form of notational simplicity

I don’t think that is accurate. Currying is about transforming functions that get multiple parameters into a sequence of functions, each of which takes one argument.

That is still a somewhat imprecise description, but I think an example would be more clarifying than going deeper into the theoretical details: If we take sum as non-curried function, it takes two integers to produce another one, the type is something like (Int x Int) -> Int, and in practice you call it like sum(1, 2) which evaluates to 3.

The curried version would be one function that given an integer a returned a function that given an integer b returned a+b. That is, sum is transformed into the type Int -> (Int -> Int). Now to calculate 1 + 2 we should first apply sum to get a function that sums one, like sum1 = sum(1), where sum1 is a function with type Int -> Int; and then apply this new sum1 function to 2, as in sum1(2) which returns 3. Or in short, dropping the temporary variable sum1, we can apply sum(1) directly as in (sum(1))(2), and get our shiny 3 as result.

If your language uses space to denote function application, then you can write that last application as (sum 1) 2. Finally, if application is left associative, you can drop the parenthesis and get to sum 1 2, which, is arguably, pleasant syntax.

1. 3

because your programming language does not have variable assignment

Just use a different variable as you should in the first case as well and it works just fine.

let x = f 0
y = f x
in ?somethingWithY


Also that’s a bad explanation of currying.

I will avert my eyes while the compiler does an assignment to a temp variable and pretend it didn’t happen

You have a negative reaction to FP for some reason which leads you to write these cheap jabs that are misinformative.

1. 2

I have a negative attitude to mystification. I don’t like it when reasonably simple programming techniques are claimed to be deep mysterious mathematical operations. Your example, is, of course, an example of why these “fancy semicolons” are needed when it is scaled up. Imagine how hard it would be to track a state variable, say an IO file descriptor around a program if we had to do fd_1, fd_2, fd_n every time there was an i/o operation - keeping these in order would be painful. The “combinator” automates the bookeeping.

The explanation of Currying is perfectly correct, I think, but I’d like to hear what you think I got wrong. There’s not much to it.

In much of mathematics, all of this is just a notational convention, not a endofunctor on a category of sets. The author, who is at least trying to make things clear, could have simply written:

The notation is simpler if we write “f x” to indicate function composition instead of “f(x)”, otherwise it gets cluttered with parenthesis. To avoid ambiguity with multiple arguments, only single argument functions are allowed and we take care of multiple arguments by using functions that produce functions as values so, instead of f(x,y,z) the value of f1 x is a map f2 and f2 y produces a value f3 and f3 z then is equal to f(x,y,z). Equivalently, f(x,y,z) = ((f1 x) y) z.

I think FP is an interesting approach. I wish it could be treated as a programming style instead of as Category and Lambda Calculus Notational Tricks To Impress your Colleagues.

1. 2

Functions take only one argument. So it’s really taking a (x * y * z), or an ‘x’ and a ‘y’ and a ‘z’. Currying is taking a function that takes an (x * y * z) -> w and transforms it to (x -> (y -> (z -> w))) aka (x -> y -> z -> w) this is useful because it allows us to create little function generators by simply failing to provide all the arguments. This isn’t simply a notation difference though because they are completely different types and this can matter quite a bit in practice. While yes there is a one to one correspondence between the two, that’s not the same as a “notational difference”. Tuples are fundamentally different objects than functions that return functions and this difference matters on a practical level when you go to implement and use them. You can say that it’s simply a notational difference but it’s untrue, and implicit conversions from one to the other does not mean they are “the same thing”.

1. 1

In Haskell functions may take only one argument. In mathematics and in programming languages, it depends.

1. 1

https://math.stackexchange.com/questions/2394559/do-functions-really-always-take-only-one-argument

In essence, it doesn’t depend. The notation depends but the notation represents one thing. f(x,y,z,w) is an implicit tuple of x,y,z,w. Without this there’s no concept of like domain of a function. This is all philosophical waxing but once you talk about currying it starts to matter because it affects what things are possible because not all arguments are provided at once. You could argue that objects and mutability sidestep this but I’d also argue that mutation within a function begins to deviate from a well defined “mathematical” function. That may be fine for you, and that’s okay. However since this conversation is primarily about definitions and we talked specifically about the mathematical way of modeling programming with functions yknow it matters.

For example in javascript the difference between f(x)(y)(z) and f(x,y,z) is literally different computations, and while there are times you can convert between the two freely, there are things that f(x)(y)(z) can do that f(x,y,z) cannot. For example I can use f(x)(y), to create a callback to defer computation with because f(x)(y) returns a function which takes a “z”. That’s genuinely useful. Now you can meaningfully argue that with objects you can do the same thing and that’s great but this is about functions and function passing. So it is actually meaningful to describe what you can and cannot do with these things.

1. 2

This is all philosophical waxing but once you talk about currying it starts to matter because it affects what things are possible because not all arguments are provided at once. You could argue that objects and mutability sidestep this but I’d also argue that mutation within a function begins to deviate from a well defined “mathematical” function.

Very little in programming is a mathematical function. Even something like (==) : a -> a -> bool isn’t a function, as its domain would be the universal set.

Also, I don’t think all mathematical functions are curryable? Like consider the function f[x: R^n] = n, which returns the number of arguments passed in. I don’t think there’s a way to curry that.

1. 2

A year or two ago I wrote an Idris function that took an arbitrary number of (curried) arguments and put them in a list (and gave you the argument count). From what I remember it used a type class with one instance for (->) (the accumulator) and one for the result type, and a lot of type inference. I’ll dig it out later.

Edit: That was an already-curried function. You could potentially automatically curry f[x: R^n] using the same technique since, in Idris, tuples are constructed like lists: (1, 2, 3) is the same as (1, (2, (3, ()))), so you could deconstruct a cartesian product while simultaneously producing a chain of (->) function constructors.

1. 1

Both of these points while interesting, and I think important questions to ask, don’t affect the position that currying is not simply a notational difference.

2. 1

In essence, of course it depends, but it’s trivia. The course notes for the mulivariate calc course at MIT begins “Goal of multivariable calculus: tools to handle problems with several parameters – functions of several variables.” I’m amazed that some Haskellian or Curry Fan has not intervened to correct the poor fool teaching that course all wrong - “Excuse me, but those are not multiple variables, they are vectors! Please write it down.” If you did say that, and the Professor was in a good mood, she’d probably say: yes, that’s another way to look at the same thing.” And if you then insisted that “a well defined mathematical function” has a single variable, well … As usual, the problem here is that some trivial convention of the Haskell approach is being marketed as the one true “mathematics”.

I have no idea what a “mutation within a function” would mean in mathematics. Programs don’t have mathematical functions, they have subroutines that may implement mathematical functions. There is no such thing as a callback in the usual mathematical definition of a function. Obviously, within a programming language, there will be differences between partial computation or specialization of a function and functions on lists. You seem to be mixing up what programming operations are possible on subroutine definition with the mathematical definition of a function - unless I’ve totally missed your point. Obviously, for programs there is a big difference between a vector and a specialized function. But so what?

1. 2

You have confused operads with categories, I think.

1. 1

You can be upset about it, but currying isn’t simply a notational difference from multivariate functions.

1. 3

Reminds me a bit of intercooler, which I’ve always admired.

1. 1

looks cool, curious about the jquery dep though…

1. 1

yes, I really liked the idea of intercooler when it came out, never used it though.

I’m sure this can be easily implemented in stimulus though (with a stimulus-friendly syntax)

1. 4

I host all my static nonsense on Gitlab Pages, and its CI is more than enough for what I need to do with it. One simple git push and minutes later, I’m good to go.

1. 3

Very cool. Awesome website too, very fun design.

1. 2

I’m currently using Pollen. It is pretty neat :) https://docs.racket-lang.org/pollen/ It’s intended for books, but I could see it easily being used for writing and publishing blogs, like this one: https://thelocalyarn.com/excursus/secretary/

1. 2

I started by working at startups as a designer. I did basic front-end (html, css, light javascript) for years until I discovered Backbone at a company I was at, which was a revelation to me at the time. From there, I discovered React and decided I didn’t want to do anything else. So I found a startup willing to hire me as a front-end engineer and here I am, a few jobs later, a senior-ish FE dev. It seems to be pretty easy to find work (even as a junior dev) in the SF Bay Area, fwiw.

1. 5

No one owns anything.

1. 3
1. 1

Elm still looks completely foreign to me, no matter how many articles I read about it :(

1. 2

You just gotta start writing code.

1. 3

or: just do whatever you want to.

1. 8

This seems more suited for HN.