It feels like we're back in 1900 when anyone's clever idea (and implementation) can give huge performance improvements, such as Ford's assembly line and Taylor's scientific management of optimizing shovel sizes for coal.
yes, it also feels like we are going to lose our just-in-time global shipments of anything to anywhere any day now. It will soon feel like 1900 in other ways.
I'm surprised there are no UTF-8 specific decode instructions yet, the way ARM has "FJCVTZS - Floating-point Javascript Convert to Signed fixed-point, rounding toward Zero"
FJCVTZS isn't really as specific to Javascript as the name suggests, it actually copies the semantics of an x86 instruction, which JS took its semantics from.
JS runtimes do use it but it's useful anywhere you need to do what x86 does, which obviously includes running x86 binaries under emulation.
I worked on this project for a week during the FB team matching process.
I had previous Haskell experience, but what struck me was how irrelevant that was.
To their immense credit, they had managed to use Haskell to write an entirely entreprise focused, "boring" business rule backend serving millions of QPS, and people who were not Haskell fans could easily use its sensible DSL to accomplish their goals.
Way too many Haskell projects are about Haskell itself, so this was really fascinating to see.
Haskell could be a great practical language if some constraints were introduced, e.g. limiting the language extensions used. https://www.simplehaskell.org attempted to do this and, currently, https://neohaskell.org is going in the same direction. After all, Haskell '98 is not that hard.
Personally, I think Haskell, or something like Haskell, is going to be reasonably popular in the near future. Functional programming and an expressive type system are great for ML-powered synthesis. You provide the type signature, and the machine fills in the function body. Furthermore, with dependent or refinement types, the solution can be verified to be correct.
Maybe I'm completely wrong (as an outside than never touched anything ML other than OCaml), but Idris 2 does seem like a "clean Haskell" minus the laziness.
I'm not fully convinced. FP is such a different paradigm than the leading imperative/OO design that most are comfortable with. Other languages that are too different like lisp, forth, Apl, Haskell, and Prolog are just too different for the average person IMO. I've given Haskell/OCaml/F# a go a few times and enjoy learning new paradigms and it certainly didn't click for me. I have a feeling it'll be even harder with more normal people not into this as a hobby.
Here is how to read a text file in Haskell (I assume a standard way):
I could be biased, but it certainly seems like Python has a lot less conceptual hurdles here. You basically specify a filepath and then for loop through each line and print. The Haskell solution requires more steps and theory.
I know Haskell is a very awesome and cool language and super powerful for all kinds of uses that Python may be inferior at (example compilers). You'll get no argument there. I'm just pointing out that I think wide adoption may be difficult. I drank the koolaid and read dozens of blog posts and a couple of Haskell books and really wanted to make it work. I'm an engineer and like math and puzzles and learning new programming languages...and yet I couldn't make it that far (without sinking a whole lot more time into it than I had) and ultimately gave up.
It's not really that Haskell is "powerful", but the type system will catch a lot of errors for you and make refactoring much easier.
Also, I wouldn't recommend starting FP with Haskell. It's hard, mostly because of the monads (and laziness can make things more confusing too). Also the syntax which is confusing because indentation is meaningful in some places, but not others.
On the other hand, a language like Scheme is really super easy. Even OCaml is super simple if you stick to the classic ML subset of the language which can take you a very long way. These languages have been using to teach programming to complete beginners. Seriously, OCaml is arguably simpler than Python, and without doubt order of magnitude simpler than C++.
If you're familiar with things like lambda, closures and functions like map or filter in Python, you already know most of what you need to write OCaml code.
> FP is such a different paradigm than the leading imperative/OO design that most are comfortable with.
I don't think most of FP is at all hard for most programmers to understand. Hell I interviewed plenty of Javascript devs that couldn't solve a simple fizzbuzz level question because they didn't know how to do for loops - they only knew how to use `.forEach()`!
The hard bits in Haskell are:
1. Purity. I get it, but it definitely makes things harder.
2. Weird syntax: pervasive currying / single argument functions / lack of grouping syntax / waaaay too many operators, etc. E.g. from your link:
let singlewords = words contents
list = f singlewords
This is just a collection of words. No clue of what is a function call, what is a variable name, etc. Allow me to recreate the experience of reading Haskell, if you think the above is reasonable:
file read lines put
lines iter while cbr empty
for do <~> x IO::print
3. General unfriendliness to people who aren't hardcore Haskellers. E.g. suppose I want to match a regex. In Go, Python, Rust, Javascript, etc. there's one obvious way to do it. Haskell? How about you pick between 8 alternatives... https://wiki.haskell.org/index.php?title=Regular_expressions
There are other flaws, like global type inference & lazy IO, but I think those are the main ones.
Haskell doesn't have operators, it's based on expressions consisting of function compositions, some of which can be infix and look like operators.
> This is just a collection of words. No clue of what is a function call, what is a variable name, etc.
That's by design, because all of them are expressions that can either reduce immediately or require runtime data to reduce fully.
> How about you pick between 8 alternatives...
How about you pick either of those and start using for real, and then come to the point it either works well or you find inefficiencies to look specific alternatives for? It doesn't take much.
The Haskell version parses the contents of the file. One answer also explains how to lazily read the file to process it as it's read, using the ByteString package. I think part of the overhead here is due to this lazy processing, plus the fact that there are basically 3 String in Haskell: String, ByteString and Text.
The python version simply loads the whole file into memory. The equivalent Haskell would be to call Data.Text.IO.readFile. What would the python version of the lazy parsing / processing of a file look like ?
There were several Python versions shown at the link and the latter one that I was referring to does not read it all into memory. It loops through each line in only three lines of code, not like 1/4 of a page.
I tried just pasting the code into the window, but never learned how to format HN on mobile. Sorry for the confusion. After the colon there are indents, so 3 separate lines.
with open('testfile.txt') as f:
for line in f:
print(line.strip())
I think Haskell seems harder because it's built on another set of abstractions (laziness, typeclasses) where Python abstractions (iterators in this case, plus the with statement for resource acquisition/cleanup) are more common, but I could be wrong (I've been working with Scala for close to a decade now so functional style looks more familiar that imperative now.)
if you want the oop style you can just change "foo bar baz" to "bar `foo` baz" which is effectively the same thing as doing bar.foo(baz), because for some reason people are obsessed with passing an argument by putting a dot after it.
> The Haskell solution requires more steps and theory.
Really? The suggested Haskell solution is
main = do
contents <- readFile "test.txt"
print . map readInt . words $ contents
which is no more complex than the Python code. The entire file contents is read as a String into content. words breaks it into a list of words, and readInt parses each word into an Int. Finally the list of ints is printed.
yes, it looks all good, until you want to change it. For instance, to make the file name a CLI parameter, you need to understand things like type classes, specifically Monad, Functor and Applicative. You may need a long time to be at ease with these things and a superficial understanding will not take you very far. In Python, it'll take you a few minutes to do the same thing.
What do you mean by "long time"? Why wouldn't it apply just the same to some Python file that defines a Maybe with a bit of unwrap and bind and orElse or whatever?
Instead of things going boom and spewing a stack sometimes they just go Nothing instead, you don't need much more understanding than that. There is a lot of syntax in Haskell that is somewhat hard to understand at first but you don't actually need it to write stuff yourself.
This idea that you need to talk a particular way and be able to teach CS theory at uni and whatnot to build stuff in Haskell is probably not very healthy.
Long time, I mean possibly several weeks of full-time studying for an intermediate Python or C++ programmer.
I'm not saying you need any CS theory to write Haskell or that it's super hard. But I think the learning curve is pretty steep, and it's hard to write code without a good understanding of the concepts. Just tweaking until it type checks isn't going to cut it.
Consider this code. Generated from ChatGPT. This is supposed to be a simple command line option parsing. I don't think it's obvious what all the operators mean.
Sure, you can try to reuse this, and extend it. But I think sooner than later you'll be stuck with some undecipherable error messages and you'll have to sit down and understand what it all means.
data Options = Options
{ optVerbose :: Bool
, optInput :: String
} deriving Show
optionsParser :: Parser Options
optionsParser = Options
<$> switch
( long "verbose"
<> short 'v'
<> help "Enable verbose mode" )
<\*> strOption
( long "input"
<> short 'i'
<> metavar "FILENAME"
<> help "Input file name" )
This is a really good point. I have coworkers that don't really code, but can use ChatGPT to help them put together a Python app that does what they need with some common sense changes. I don't think I could even do the same with Haskell with a fair amount of coding experience+ reading up a lot on Haskell over the years. It may be obvious to those select few who are drawn to Haskell, but I think they greatly underestimate the challenges for the average person. That's the essence of what I've been saying to the parent thread that believes a subset of Haskell will become popular some day. I could be wrong, but just can't see it.
It is obvious, as long as you know what Functors and Semigroups for custom data types are. If you don't know it, you can still use it freely without fully understanding the meaning of `<>` and `<$>`, because they are written almost as plain bullet points of components to treat as a single whole.
I'd say a lot more is going on there conceptually than the Python code. Imagine through the eyes of a beginner. You have some main do thing, then you appear to read it all into memory and assign a variable, then you do a bunch of composition to words and readInt and map it to print?
With the python version, you see the file handle as a variable and then for loop on that iterable and you can print each line or parse it however you want. Even when I was learning to program and had no clue what an iterable object was, there seemed to be an obvious three line idiom for processing text files that was easy to use.
I think the issue that many people have with Haskell is the order of expression evaluation is not structured left-to-right and top-to-bottom. At least it's what makes it difficult to read Haskell for me. Compare it with F# (and OCaml family in general):
open System.IO
(File.ReadAllText "text.txt").Split()
|> Seq.map int
|> Seq.iter (printfn "%d")
It doesn't really matter on simple expressions but as you keep chaining the operations the reverse order gets more difficult to follow.
Haskell even on a bad day is radically more sane then all of these languages doing this bizarre obsession with foo.bar() instead of bar(foo), because they only allow overloading on the first arg. semantic indenting. type inference. automatic laziness. it's just another level.
Every time I try to work on someone's Haskell code, I'm confronted with a slew of custom infix operators, and I find my previous experience is completely irrelevant as I learn the new DSL the authors chose to write (which more often than not also involves flexing their brain as hard as they can).
But that's like half of computing.. every new tool the world inflicts on you, configured in Jojo's Awesome Configuration Language, with some arbitrary made up grammar punctuated by Tourette outbursts of special character line-noise.
That, or YAML, then a tool to template and generate the YAML, and then a stack of tools wrapped around that, ad infinitum.
A little learning is the cost of not having to write the thing yourself. On the other hand, hell is the non-composable tower of babel that is computing. Total employment by exponentially compounding incidental complexity.
The amount of arbitrary glue, configuration and "cool things" I need to learn-and-forget for every new project is an order of magnitude less than any other language I've used in anger.
The fact that people do it in the ordinary language, so you can click through to the operator definition and see immediately what it does, makes it a lot less taxing IMO. Even if the code is quite complex, figuring out what an actual function does is 10x easier than doing the same with a magic annotation, which is what you have to do in that situation in most other languages.
Right, now imagine the templated YAML mess implemented in Haskell together with the app. By someone smart enough to liberally use Haskell's most complicated features
I'm sure it is super cool and immediately comprehensible for an independent project. I'm actually really fascinated by programming languages like APL that take it even further, I'd like to try some of those out but I don't have a great fit for a project to use with them.
But all I can think of when I see custom operators professionally is how much of a nightmare it would be the second one has to onboard a junior developer onto the project.
It's super cool, but I'm not sure immediately comprehensible. I can't even read my own Haskell code after a few months away from it. You end up using other people's infix operators from the libraries and it's easy to forget what they are.
That's interesting, because Haskell is the only language in which I can easily read code written by others (and in "others" I include "myself three years ago").
> Way too many Haskell projects are about Haskell itself, so this was really fascinating to see.
It seems like Haskell is a good match for the requirements in this case, too. Implicit concurrency and enough robustness from the type system that new filters can be deployed directly to production plays to the strengths of the language. It doesn't feel like the usual solution in search of a problem.
My school dentist always botched the anesthesia, and afterwards I had to grind my teeth for three days to make them fit together again.
I never told anyone because adults kept saying dentistry hurts so I assumed it was normal. I didn't realize how fucked up this was until I went to college and experienced a competent dentist for the first time.
Not sure if the anesthetics have got better or if it's just a skill issue, injecting it in precisely the right place?
I had problems way back in the 90s with them not working too well on me. But my current dentist gets it perfect every time - properly numb very fast, but remaining fairly localised.
Tbh if you've never done either, I can absolutely see why getting on and riding a machine 1000x your size is a bigger deal than seeing various animals from a distance.
Yep, I work on low level networking software professionally and this post is largely meaningless dribble and is probably motivated by grandstanding.
It’s like an engineer who says “how does a screen show black” and then says “nope” to every response. It’s maybe a way to make people think, but beyond that the negativity and grandstanding of it is ultimately a turn off for many receivers which eventually either then has them bully others this way or deters them from the field, depending on how it affects them. There are far better teaching methods that work better for everyone and teach faster and result in higher accuracy and retention.
I thought you were probably exaggerating, but yes. I've never heard anyone make anything resembling any of those claims.
What I have said is something to the effect that if TCP isn't reliable over a given path, there's not a whole lot I can do about it as an application engineer short of making my own ad hoc, informally-specified, bug-ridden, slow implementation of half of TCP inside my own app, which I'm not going to do.
> 14. Weird networks that are not transparent to standard protocols are an aberration. I can safely ignore them.
I certainly can and will. If you wanna run an RFC 2549 network, I'm going to spend approximately 0 seconds making my app support it. If you want to do something weird, you make it work. I'm going to optimize for the other 99.99999% of customers.
Doesn't the author basically admit that when he prompts someone else to write "falsehoods programmers believe about TCP"? After all, if the author did have the understanding himself he could do it himself.
The reset of the writing just laments the pain of using products that make incorrect assumptions – continuing in same lamenting from the quoted segment he includes. It almost has nothing to do with TCP at all, so it is not clear where the parent comment here got the idea that it was trying to teach something about it.
The screen knows what color it displays at all times. It knows this because it knows what it doesn't. By subtracting what it does from what it doesn’t, or what it doesn’t from what it does (whichever is greater), it obtains a difference, or deviation. The controller board uses deviations to generate corrective commands to drive the display from a state where it does not display black to a state where it does, and arriving at a state where it displays black, it now doesn't display anything.
Each of the pixels is actually a little shining eye which watches your every move. When the pixel’s eyelid closes, that pixel turns black. That’s why they call it putting a display “to sleep.”
I like your explanation, but to be fair, it depends.
Some displays are implemented with dual-eyelid technology for the blackest of blacks. Naturally, like all genius engineering, we see this in nature: cats.
It depends afaict. OLED screens have a per-pixel light, and they turn off pixels to make black. LCDs have a single large backlight and pixels that the light shines through and they can change color (but not turn off) so in that case they turn as opaque as possible, but don't completely block the light.
I don't think you're taking into account the context or intended audience. It's a casual forum message posted in reply to someone else's message.
They have not written a "falsehoods programmers believe" article. They have proposed that one ought to be written and have given a starting point for what it might cover.
They offered their list to "get the ball rolling", confirming that they don't see it as a finished product.
They sent it to other readers of the same forum, who might be expected to have more knowledge of this topic, not to whoever runs across it on the front page of HN.
Every point is not self-explanatory, and some are clearly true (while the assumption is they must be false). For instance, it surely is true that any name will fit in under a Terabyte of text, if it can be encoded at all (and assuming the contrary is counter-productive). Claiming you should not assume any name can be spelled in Unicode is absurd as well. And, yes, it's perfectly fine to assume that if your system must have "real" (i.e. proved by any kind of document) names, you won't have to deal with Klingon names (even though it isn't a huge relief, honestly, since they still can have pretty much whatever format). For most systems, even more restrictive assumptions than that are totally fine.
You don't have to defend the "original" post just because it was patio11's. This idea was awful and stupid from the very beginning, and every new post of this "series" just repeats the offence.
> People’s names fit within a certain defined amount of space.
For any given fixed size that people use in practice, there is a name that does not fit. This is saying "use a variable-length field for names, because there are always edge-cases".
> Jullien was born in Sisteron, Alpes-de-Haute-Provence, and was baptised Louis George Maurice Adolphe Roche Albert Abel Antonio Alexandre Noë Jean Lucien Daniel Eugène Joseph-le-brun Joseph-Barême Thomas Thomas Thomas-Thomas Pierre Arbon Pierre-Maurel Barthélemi Artus Alphonse Bertrand Dieudonné Emanuel Josué Vincent Luc Michel Jules-de-la-plane Jules-Bazin Julio César Jullien. His father was Antonio Jullien, a violinist. The explanation of his unusual number of names is that when the time came for the baby to be baptised, his father had been invited to play at a concert given by the Sisteron Philharmonic Society, and considered it only polite to ask one of the members of the orchestra to be godfather: but since every member wished to be considered for the privilege, he was christened with the names of all thirty-six members of the society.
I'm pretty sure that patio11, having spent his life in Japan, would know that technology like SING glyphlets exists because of this exact issue.
(and before you answer "what are you talking about, it is in Unicode?", these characters are literally added after the relevant issue surfaced, and some characters like 𱅒 (U+31152) are recent additions that don't even render properly)
No, he one proved that other people don't need to put up with your bs if you try to break conventions. Hence your use of ASCII "Prince" being entirely adequate.
Besides, AFAIK he only changed his stage name, not his legal name.
I wonder what he means by France having a “weird” naming system in common use. As far as I can tell, the traditional French naming system works exactly the same way as the traditional American one (except that it’s more common for French people to have several middle names rather than zero or one, but I don’t think that’s too rare in the US either).
Maybe he’s referring to the fact that some last names are two words (e.g. Marine Le Pen), but I don’t think that’s very common…
Anyway, it could be anything, so I wish he’d said!
Perhaps he is thinking of how marriage does not change your last name, but rather gives you an extra, optional last name. [1] The French ID card has two last name fields!
Err. It still does by default change your name (if you're a woman). But you can ask and keep your 'maiden' (ugh) name or have both. It gets a bit trickier for kids' family names...
Anecdotal, but the only people I've met in the US with more than one middle name are people who originally came from another country.
Although, I wonder if maybe that is enforced by the fact tha legal forms and similar typically assume you only have first, last, and optionally a (single) middle name.
George Herbert Walker Bush comes to mind as a native son of the US with multiple middle names. He used H. W. in politics, but that still includes some whitespace and non-traditional characters.
i thought this list was also self-explanatory. i didn't have a hard time thinking of counterexamples to any of the points, which is not true of patio11's article. but what's self-explanatory depends on your knowledge base. maybe i just know less about foreign cultures than i do about tcp
This. If these lists contained things that programmers actually believed and explained why they are false, they might actually be useful. It's hard to imagine an unsupported assertion that an ambiguous statement is "false" and yet its contradiction is also "false".
I agree. This isn't even a good one of those lists. It's more like "dubious pedantry to make me feel smart about my TCP knowledge".
1-4. Yes we know about the 2 generals problem. And yes we know what "reliable" means in this context.
5-6. This is just stupid.
7. Obviously not true. Nobody thinks this.
8-9. The reasons for and flaws of Nagle's algorithm are well known.
10. This isn't even true. Most of the time you don't need to care about it. That's the whole point of abstraction. You need to care about it if you are doing extensive performance optimisation, but usually you aren't.
11. Again untrue. You can think of TCP as a two way pipe. Again that's the whole point of abstraction.
12. Not sure exactly what they're trying to say here but again it's very well known that TCP and UDP are pretty much the only protocols that are likely to work on the internet.
13. Ditto. We all know why so many protocols are "over HTTPS", e.g. DoH.
14. This isn't a technical point.
15. Dunno what this is talking about but I'm guessing it's along the lines of "a byte is 8 bits", i.e. it is actually true in the modern world.
Right, I was about to comment that. One of the first ones I remember was this one, about addresses[1]; or this one, about names[2]. Both provide examples and information, which is the only thing making the whole article useful.
I think the original "names" and subsequent "addresses" were useful in that a conclusion(that programmers should embrace defeatism and refrain from parsing or evaluating or even trying to separate them into fields) can be drawn, and the lessons learned were slightly more specific than often realized...
I noticed that too and thought I was missing something. Some cool resources that are actually decent for network programming:
https://beej.us/guide/bgnet/ -- Covers what abstractions the OS provides for network programming and the guarantees that are possible.
https://www.madwizard.org/programming/tutorials/ - This is the very first ever good tutorial I read on socket programming. It's OG winsock. Introduces network programming from the most basic level. Aimed at C.
When you understand these guides you'll learn that how you structure your entire programs networking depends on whether you want to use blocking or non-blocking sockets. If you go with blocking you'll probably be using threads or processes. Otherwise you can't do any other work. With non-blocking it will be more about polling sockets and eventually you might end up with something resembling an event loop.
Until you come towards to the current approach to networking which is mostly async await -- an event loop works with non-blocking sockets, watches them for changes, and passes data from them to event handlers. There's a lot more that can be done on sockets to effect things like how data is flushed, how TCP errors are handled, and so on, but its a good start.
I think these lists are often primarily intended as humorous, and perhaps a way to get you thinking about exceptions, not as a way to teach you more about the topic.
“Falsehoods programmers believe…” articles are designed to make you THINK about problematic assumptions. They are not like the 10 commandments and they are not decrees of absolute truth.
Now imagine how much time could have been saved globally if one person spent half an hour writing a short description of why each point is false instead of making hundreds (or thousands) of people spend hours thinking about and researching every one of them. You're probably left with more knowledge in the end if you're not spoon-fed by the author, but how many of us need really deep knowledge of the TCP inner workings?
Yep, the original "names" one was mostly written so negating each of the points gave you the exception you needed to handle. Even the cases written with both were done on a way it was obvious the negation didn't apply universally, so both worked.
I look at "Falsehoods programmers believe..." articles as a good source of test cases. If I'm parsing a date (don't do that), I'm going to look at "Falsehoods programmers believe about dates" to help build out my list of unit tests for that function. Same for names, street addresses and so on.
Back in the day I ran Bochs in all its 4 Bogomips glory on a university IP address and went to IRC channels where script kiddies were "trading root".
I let them go first, and watched through an instrumented terminal how they clumsily installed a rootkit, then inevitably refused to give anything in return and laughed calling me a noob.
Their laughter was short lived.
I had even spent quite a bit of effort kludging the kernel to report much higher specs than Bochs could deliver, but all that effort was wasted because no one knew how to check.
reply