John Carmack: “I just dumped the C++ server I wrote for a new one in Racket”
twitter.com
twitter.com
I think this is a consequence of a lot of these languages getting a lot nicer tooling recently, as well as other FP ideas being pulled into newer languages.
I had the great fortune of meeting Steve Bourne, inventor of /bin/sh. If ever there was a guy who could accept any and all accolades it would be him. Instead he was most gracious and humble and spent all his time showing interest in our work as well as answering our questions about the invention of the shell and Unix.
Speaking of; did you know he was the first alpha tester of Unix? When Ken Thompson and Dennis Richie were writing it they would hand the magnetic tapes over to Steve Bourne and have him test it.
Most indie dev. are like that, they don't have anything to show but act like they know everything and that everything they say is pure gold.
I think it's sort of made its way around as the way to act if you know what you're doing and that's a shame. I know a lot of great devs who are lost in the shuffle for not being boisterous enough.
I'm of the opinion that it's not. And, it provides a really poor example to the younger people in the field.
I've known a lot of programmers. Many of them far smarter than Linus. Funnily enough, the better they were; the nicer they were.
Seriously, there's no productivity benchmark beyond which you shouldn't treat people with respect. There are broken cultures where you can get away with it, but you'll still be an asshole.
Linus is an asshole not because it's some deep essential part of his nature, he's an asshole because people give him a free pass.
While it's not preferable, I think that we can be understanding of the fact that people can sometimes have outbursts due to stressors in their life. That said, whenever I've seen people bashing a Linus outburst, I've gone and read said outburst. It's never as bad as the "tech press" make it out to be.
Sure. The question is, do the rest of us treat those incidents as mistakes where somebody went over the line and behaved poorly, or do we defend the behaviour and even try to argue that it's a sign of good project management that should be emulated because it 'tells it like it is' and keeps away the 'idiots'? Sadly the latter is a common attitude, as seen in other comments in this thread.
The level of rudeness in conversation is very dependent on cultural background and those ignoring it display cultural insensitiveness
Europeans are more straightforward than Canadians and Indians where everything is said in a mild passive-aggressive tone that goes nowhere.
"Mauro SHUT THE FUCK UP"
"I don't _ever_ want to hear that kind of obvious garbage and idiocy from a kernel maintainer again. "
"fix your approach to kernel programming."
"There aren't enough swear-words in the English language, so now I'll have to call you perkeleen vittupää just to express my disgust and frustration with this crap."
It's ridiculous to claim that that's just avoiding unnecessary civility. Those statements aren't "blunt", they're just him being a dick.
But in the written medium it really come across is the most harsh way.
But while maintaining the kernel sometimes he needs to get the point across and saying "this is unacceptable, I am disappointed" will not work.
For those examples, when reading the context I (usually) agree with Linus (and with his attitude), and this usually happens when the situation has been building up and people keep repeating those mistakes.
Also, there are people much worse than Linus on the LKML (and subsystem lists), also some people are very polite and helpful.
What I find remarkable is that people always talk about the same half-dozen remarks - from an history of 20 years of kernel development completely in the open.
Linus is a fucking remarkable example of civility. He just doesn't have an office where he can shit all over people in private, like so many managers.
If everybody was just saying that those were unfortunate incidents where he lost his temper and agreed they were inappropriate then this debate wouldn't keep happening. Some people aren't prepared to admit that Linus is ever at fault in any way during these episodes. There is even a group of people who think that those episodes are examples of 'telling it like it is' and 'sticking it to the PC crowd' and thus should be replicated as much as possible to make sure your project isn't 'swamped by idiots'. Unfortunately some of the people with that attitude maintain open source projects (and have downvote powers on HN).
I have found buffer overflow bugs in widely used open source projects that I have not informed the developers about, because when I've made previous bug reports they acted like assholes. I don't feel inclined to open myself up for public humiliation just to contribute to their project.
Except the people he usually deals with in a harsh manner are not inferior, rather, from the examples, it is usually the top collaborators
> I have found buffer overflow bugs in widely used open source projects that I have not informed the developers about, because when I've made previous bug reports they acted like assholes
I understand, but did you follow the bug reporting procedure?
Also, some projects may act polite towards outsiders then direct criticism (and bugs) to /dev/null
I don't think it's the best way to manage anything, but I also don't think these outbursts are a big deal.
Your commend would be relevant if my comment was the top of a thread or something. Take a look at the context of the conversation. I wasn't popping in out of context out of nowhere and saying "Linus is an asshole, look at these comments!". I was responding to the specific assertion that these asshole-ish statements can be attributed to cultural differences. I in no way disagree with the idea that "Linus was being a dick in these cases" is very very different from "Linus is a dick".
Also, Linus isn't representative of Finnish or Swedish culture (none of which put a lot of stock in assholishness) as much as he is representative of early 90's hacker culture and he never had to grow out of it. It doesn't work as well for a guy with a lot of power though, it isn't cool when he kicks downwards.
I'm not saying he's representative, but it certainly plays a part.
Unless you want "Continental Eastern European", which makes Linus sound polite?
kryptiskt is right and not nitpicking. You are trying to take widely diverse people groups and lump them all together based on a general ignorance of the places you are talking about.
Of course it doesn't make sense, that's why I never said it, but the cultures share some traits, even across language borders.
Having lived in more than one country in Europe I think I know something about the differences (and similarities) between them.
Linus is of course from the Swedish-speaking minority in Finland, and I don't know if it translates. But anyways, like others I find it a little weird that you speak of a singular European stereotype. It's not something I can understand at all, really, but I suppose yours is an outsider's perspective.
I also think that your opinion on why Linus behaves as he does is wishful thinking, sorry. There's a decent chance he'd take his ball and go home if the above were done. That would be bad.
But if you cannot take having a new one teared when you do something stupid - you are in the wrong field. Bullshit, stupidity and thin-skinniness should not be tolerated.
But it seems there is a kind of tradition among hackers of people that are exceedingly smart but also jerks.
They get away with it if they are sufficiently smart, because many hackers tend to value a certain kind of cleverness above most other things. And honestly, I would rather deal with a smart jerk, as long as he/she was not trying to feed me bullshit than a friendly but ignorant buzzword-slinger.
Having said that, let me repeat that I would prefer a friendly smart guy over both of these extremes, and so far, I have been lucky.
What's intolerable is when untalented people cargo-cult Jobs or Linus and pretend that their personality is what caused them to succeed. There is nothing more scary than an untalented manager reading one of the many 'inspirational' leadership books about Steve Jobs - they are likely to pick up every single wrong lesson.
Has anyone ever complained that Terence Tao is apparently a genuinely really nice person? People would still work with Tao if he was a misanthropic asshole because he is probably the smartest person in the world, but it's not like being a kind and generous human being detracts from his genius.
We haven't seen Carmack when someone tries to contribute naff code to one of his game engines. He doesn't develop in the open the way Linus does.
I also don't like strong emotional confrontation.
Can you see why I wouldn't want to work with someone abrasive like Torvalds? Part of me will always be on edge expecting to be chastised, even if that were never directed to me. So it isn't only the targets of his abrasion which are affected, but also those who think they might be targets, even if that belief is wrongly held.
I just think that his abrasiveness (even if it only manifests itself in a few circumstances) is a negative that people tolerate because he is such an exceptional project manager and programmer. The keyword is 'tolerate'.
Too often, people think that his success comes not from his technical mastery (which is very difficult to imitate) but from aggressive rants and call outs - and try to imitate those and justify it as 'well that's how Linus runs the kernel'. It's even more prevalent with people cargo culting Steve Jobs' personality flaws thinking it will make their company the next apple.
He needs to be able to trust people because he needs to merge thousands of patches and make sure nothing bad gets in.
This is the only reason you should ever do what Jobs or Torvalds have done: trust.
Romero
Yes, some other, less talented developers are being jerks and decide that they should try to hide their deficiencies by imitating Linus Torvalds. That does happen. But I'm sure that to a far larger extent, imitating the style of the great leader is just something that happens subconsciously.
That is really the reason why I disagree with nkozyra's grandparent comment. Even somebody who really knows their stuff must be conscious of how they communicate, because of the potential problems that arise when their style is inevitably adopted by those who don't really know their stuff.
http://www.amazon.com/System-International-Computer-Science-...
It was somewhat outdated by late 80's but it was still "the book" for newcomers to Unix environments.
Next, look up what AWK stands for...
He's always been humble, engaging, friendly, and most of all, passionate about what he does without becoming fanatical about it.
Either way, his tweets are always entertaining.
It's very illustrative to me of just how tribal we've become. As if it matters what language Carmack decides to use. I'm sure it's a boon to the Racket tribe that the others are now jealous of. To have the name recognition of John Carmack tweeting about your language! Imagine!
Racket is a fine enough language and ecosystem. I'm more curious about what he's building. Is this the VR-version of Facebook?
I think if we look at the history of adoption of technology, a lot of it is driven by the top 1% endorsing it. I think its a pretty big deal when high profile people endorse a technology. Social capital is as real as financial capital. Carmack has lots of social capital and it can get results. His celebrity helped launch Oculus from a weirdo company playing with 90s relics to a Serious Threat to The Status Quo and I'm sure drew in big investors and eventually Facebook's purchase of it.
>It's very illustrative to me of just how tribal we've become.
This is how we've always been and will forever continue to be.
I suppose this might be true but it's rather hard to quantify. I don't recall ever choosing to invest in and master a language from a celebrity endorsement. Some people might have -- I can't say. But it obviously does have merit because of the responses Carmack's tweet solicited so I don't disagree.
I just found that the majority of responses were of this patronizing sort. If Carmack is amongst the top 1% of programmers, as you say, and is a minor celebrity as we both know then it seems disingenuous to immediately ask him, "Why not Haskell/Erlang/Clojure/Whatever-my-favorite-X-is?" Given his previous essays on functional programming and his move to adopt C++ I think it's safe to say he knows what he's doing and picked Racket for good reasons (even if it's as simple as, "I like it."). I made the tribe observation when it became apparent to me that perhaps they were jealous that Carmack didn't pick their tribe and bring his celebrity power along to them.
I find that kind of sad and funny. I'm more curious as to what he's building than what language he's using to do it with. There are interesting things to talk about wrt the system he's building and the run-time he's building it on but that seems to go over the majority of peoples' heads. Even as a newcomer to the Racket ecosystem I think Carmack will have quite a lot to teach us as he develops this system: about Racket, the language VM, system architecture, his process, etc.
So when I said, "As if it matters what language Carmack decides to use," what I was implying was that he probably has reasons and it's more interesting to know what those are. He could have continued writing it in C++, Haskell, anything... it's what he does choose, as opposed to the multitude of choices he didn't make, that is interesting here in my opinion.
I've written a small Clojure project, maybe 3k loc. It was great fun. But when I go back to add small features I find it quite tricky. Bugs often sneak in.
If you want to write maintainable code and catch bugs early, that pretty much rules out dynamically typed languages.
OTOH in strongly typed languages with rich type systems the actual code might be uglier and more complicated because you're constructing a proof of something. The property might be week (tests needed!) or strong (tests? what tests). Depends how far the rabbit hole you want to go.
At least that's my view on this.
It's rare for the programmer to actually produce proofs that a piece of code meets the spec given by its type[1]. Those proofs are generally produced by the type checker, possibly with occasional hints from the programmer.
1: Even in Coq, detailed specs for some code are typically given (and proven) separate from the code itself rather than in that code's own type.
Statically typed languages apply typechecking as a "test" to the entire program at load time.
People have written and maintained code in typeless assembler, including for mission-critical systems. It's just more work and requires a different kind of rigor. The larger and more complex your system gets, the more useful typechecking becomes.
"Maintainable" is not a boolean, it's a cost function.
In a dynamically typed system, every expression and line of code is a liability, and requires a large weight of tests to have any confidence that it might work.
Static typing eliminates entire classes of bugs. The cost of the up-front inconvenience to the programmer is tiny compared to the ongoing maintenance costs of possibly-incorrect, we-won't-know-for-sure-until-that-code-path-executes-in-production dynamically-typed code.
This is dependent on many variables but a good rule of thumb is that for any project bigger than a doddle, it's a safe bet to just fucking use a statically typed language.
I don't want to start a discussion here on typed vs untyped so please consider everything I say to be qualified "It is only my personal opinion and experience".
I'm writing Haskell in my day job, Clojure for fun side project, OCaml because it's a nice language that's a bit underused and C++ because it's useful to know and not so evil as most people say (and it's progressing fast!). I should throw Rust into the mix because it might have a bright future.
WARNING: personal opinions and anecdotal evidence ahead!
Maybe there's a level of lisp enlightenment that I haven't reached yet but I can't just get by with writing lisp without writing tests. On the other hand I can get by with writing Haskell and OCaml without writing tests.
This is particularly true when I'm coming back to a project that I haven't touched for a few weeks. I change something and something breaks. In Haskell and OCaml I change something and compiler complains.
Maybe we'll see HaLispML one day.
BUT those guys are much smarter than us... so creating a language that combines the qualities of dynamic and static languages is probably a hard problem.
* Racket has a sophisticated contract system that allows you to enforce "type-like" properties at runtime very easily (e.g., you can say "This function should behave as an ((int -> int) -> int) function" and it will do all the necessary runtime checks to make sure that contract is honored as your program executes)
* It also has an optional modern type system, Typed Racket, that you can opt into on a per-module basis. Typed Racket modules can interact with untyped modules safely via contracts. The Typed Racket type system was designed specifically so that it's easy to migrate untyped, idiomatic Racket code to the type system, so you can write untyped Racket code idiomatically, and then go back and port your untyped module to Typed Racket with a minimum of fuss and get the benefit of the type system.
That said ...
> On the other hand I can get by with writing Haskell and OCaml without writing tests
Tests and static type-safety serve different purposes. If you end up writing tests for properties that should have been inferred by a static compiler, then you're using the language in a wrong way or you've picked the wrong language for the problem at hand.
When working with a dynamic language, I don't need to write tests just to see that my code works. It's because I work with a REPL and in terms of happy paths, that's just as effective as having a static type system.
And surely having a compiler is very cool when refactoring, however we tend to miss the fact that (a) the kind of refactorings we are doing are very superficial and for architectural / design refactorings the compiler doesn't save you and (b) in a dynamic language there is less need for refactoring, because you don't end up modelling the whole world through types.
> I don't want to start a discussion here on typed vs untyped
I'm also thinking you're making a confusion. Dynamic languages can be strongly typed. A language Clojure is very much typed. The difference is in the moment those types are used, at compile time or at runtime.
This is important, because a dynamic language like Clojure can do optional typing when you want it. Of course, something like core.typed will never be as expressive and potent as Haskell's type-system, however this leads to gradual evolution - at first you don't have a well defined shape for the data you're working with, so you can enjoy the relaxed rules and protocols of Clojure and afterwards you can start introducing type definitions with core.typed or with prismatic/schema.
As I said, I'm a developer that leans on the static side of the argument, however this debate will never be settled simply because which tool is the best depends on the problems you're trying to solve, therefore people will never agree on anything, because people are always thinking from their "personal experience".
Well, I never want to have to maintain one of your Haskell or OCaml projects. If you think you can get by with any language without tests you are wrong.
That being said, yes it is easier to deal with lack of tests in a staticly typed/compiled language than in a dynamic language like clojure/ruby/python/perl/etc.
The main point I'd like to make to you is you aren't complaining about Clojure per say, you are complaining about dynamic languages in general. It just so happens clojure is the one you are picking on.
Either way, you might like Shen (http://www.shenlanguage.org/) though it is very much academic and has few tools around it, it is very much a HaLisp, though i'm not sure about the ML part.
At this point in my learning it's more about pleasing a SAT solver than getting anything useful done... but I'm sure that will change with time.
Common Lisp does have a type system... it's just dynamic so you can hit things at run-time. This is great in development because it allows you to under-specify things that aren't terribly important (like types) at that time. However when you begin to find your code is ready to be locked in place you can annotate your function to hint to the implementation what the types should be. In particularly well-tested and heavily-typed code you can even turn off dynamic type-checking entirely for your production builds and get the performance boost from that.
Regardless of your approach and requirements, tests have a completely different use beyond ensuring type consistency. They set expectations, inform API design, and catch mistakes in refactoring; they act as a specification for the module under test. I've had plenty of OCaml code compile that still failed tests. Even in the presence of strong static typing you need unit, integration, and regression tests.
Just food for thought.
I'm doing a lot more Scala these days, which feels a lot easier to work with in the long run.
Golang, in comparison, is very transparent, WSYIWYG.
Anyway, Carmack has convinced me to take a look at Racket again. When I looked at it a few years back, it seemed nobody was using it.
But, the Arc compiler is written in Racket[1], and internally outputs Racket code[2]. "mzscheme"[3] is an early version of PLT Scheme, aka Racket.
[1] https://github.com/arclanguage/anarki/blob/master/ac.scm
[ed: and perhaps PostScript/Forth...]
Overall, I think the more languages that exist, the better. Some people think we should be moving towards more domain specific languages.
There is a balance between using the best tool for the job, and getting a large potential developer base.
Nearly every imperative language is a walk in the park after you know C++, and you can still write C++ for performance-intensive code (if necessary with expression templates et al.).
Are there more now? I remember a zillion niche pet languages from forever ago.
Now a days I see less, probably because it's not in-style to write an in house scripting language for every single new project, they tend to just use a language that is nice off the shelf.
The premise behind Racket, in broad strokes, is to provide a platform and programming language for making new programming languages. The most important identifier/keyword in Racket is '#lang' (specified at the top of a file to tell Racket which language the file is in). It's a whole ecosystem in which a multitude of languages exist and the only thing they really need to have in common is that on some level they speak Racket.
Personally, I think the above paragraph explains how exciting Racket as a language and platform is, but it doesn't sound that interesting on the surface. It does allow people to create things like this[0] and this[1], though, which displays real practical use; shaping the way you solve the problem to fit the actual problem.
[0] http://www.youtube.com/watch?v=oSmqbnhHp1c - Naughty Dog's scripting language [1] http://pollenpub.com/ - A web book publishing language
How so? I'm curious.
Edit: reference: http://seattleclouds.com/ticketfiles/8665/ios_program_standa... 3.3.2 "An Application may not download or install executable code. Interpreted code may only be used in an Application if all scripts, code and interpreters are packaged in the Application and not downloaded." So in fact the Lisp app is also forbidden (but of course Apple is free to selectively enforce)
http://www.reddit.com/r/haskell/comments/1jj40p/john_carmack...
If I'm reasonably familiar with Common Lisp, what are the main differences/advantages of Racket to pay attention to? What's the best resource (preferably online) to use to learn about Racket?
Their documentation is great, though, so it's a good place to start: http://docs.racket-lang.org/
Really it comes down to the old CL vs scheme thing, which seems to boil down to "has almost everything you need already but is huge" vs "lets you build anything you need yourself and is tiny." However, I think this is less so with Racket because, while I haven't used it much, from what I know it's more of a batteries-included scheme used for Getting Shit Done (and does a good job of this).
If I was going to use a scheme and I didn't have the requirement of needing to embed it, I'd probably go with Racket.
http://docs.racket-lang.org/scribble/
I suppose it isn't technically such a different thing from other lisps, but like most of Racket -- it's pretty well thought out, and actually works really well.
[ed: as per my other comment, see also eg:
Racket's macros are unlike any other. They are better thought of as a lightweight compiler API. Check out http://www.greghendershott.com/fear-of-macros/.
Also, the whole #lang framework is a pretty unique tool for experimenting with and extending the language, see http://docs.racket-lang.org/guide/hash-languages.html. For example, used to build http://www.greghendershott.com/rackjure/.
Greg Hendershott does some great writeups, there's more to find on his site.
You could work through SICP using Racket instead of MIT/GNU Scheme. I'm currently in the midst of this and the differences thus far have been relatively minor (e.g. Racket doesn't have `inc`, `dec` or `nil`).
I'm assuming those are trivial to add?
inc and dec I assume mean increment or decrement (I have no experience with CL) - racket/base includes (add1 .) and (sub1 .) for the same effect. If they didn't exist they would be trivial to add I think - if this isn't what inc and dec mean then I apologise.
In Scheme/Racket truth and falsity is really simple - #f is false and everything else is truthy. There's also already a null value for the empty list (which is 'true'). I don't know if nil would be useful.
In Common Lisp, unlike Scheme/Racket, nil is the null value AND the false value. In Scheme/Racket, 'nil is true unless you define it to be #f. If you wrote an if or cond expression to evaluate the 'nil in the link, I think that it would return true, whereas in CL nil is falsy (I think it is the only falsy value in CL, but I would still describe it as 'falsy' rather than false, possibly incorrectly).
e: Ah, I see why I'm not understanding you now - you're talking about the differences between Racket and SICP/Scheme whereas I made the assumption that we were talking about the difference between Common Lisp and Racket (from OP's comment). To further clarify, I believe this was my fault in comprehension, not yours in communication.
But it is how nil is defined in SICP:
'The value of nil, used to terminate the chain of pairs, can be thought of as a sequence of no elements, the empty list. The word nil is a contraction of the Latin word nihil, which means "nothing."' -- http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-15.html...
And then in a footnote to that paragraph:
"It's remarkable how much energy in the standardization of Lisp dialects has been dissipated in arguments that are literally over nothing: Should nil be an ordinary name? Should the value of nil be a symbol? Should it be a list? Should it be a pair? In Scheme, nil is an ordinary name, which we use in this section as a variable whose value is the end-of-list marker (just as true is an ordinary variable that has a true value). Other dialects of Lisp, including Common Lisp, treat nil as a special symbol. The authors of this book, who have endured too many language standardization brawls, would like to avoid the entire issue. Once we have introduced quotation in section 2.3, we will denote the empty list as '() and dispense with the variable nil entirely." -- http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-15.html...
Apologies for the confusion.
In that case, I don't think it's possible to define an exact equivalent of CL's nil in Scheme, as nil means both false and the empty list in CL -- the latter being falsy in CL and, as you point out, truthy in Scheme.
Their pattern matching is easier to extend than optima though.
SICP - http://mitpress.mit.edu/sicp/
HTDP - http://htdp.org/
Dan Grossman's Programming Languages Coursera course - https://www.coursera.org/course/proglang
The Racket docs - http://docs.racket-lang.org/
Chris Jester-Young's StackOverflow answers - http://stackoverflow.com/search?q=user:13+[racket]
This list won't be as useful to you as it was to me, because you already know Common Lisp, but hopefully other readers will find it interesting.
NB - the ProgLang Coursera course features Racket alongside SML, Ruby and quite a lot of material that will seem very basic to experienced programmers, but it's a really good introduction of some of its key features. I think this is probably my weakest recommendation to someone who already knows Common Lisp (or similar) and my strongest recommendation to someone who does not.
Beyond that, the default DrRacket IDE comes with a whole load of teaching resources bundled by default, including (iirc) resources to help build a game in Racket - this package I think http://docs.racket-lang.org/teachpack/2htdpuniverse.html.
As for differences/advantages of Racket, I would say that there are few that I'm aware of beyond the simplicity of learning the language, the great tools, and the ease with which you can get up and running. Nothing inherent to the language that I'm aware of, and I would suspect that Common Lisp is great if you're already part of that community and 'know where everything is' so-to-speak. I've heard that CLOS is better than Racket's OOP abilities.
I really do love the language, though, it's one of the easiest and most joyful experiences I've ever had with a programming language. Just maybe not a necessity if you already know CL.
Not sure Carmack qualifies as a newbie when it comes to anything programming-related.
John Carmack was mostly a C programmer up until quite recently and then started experimenting with some Functional Programming languages, and I'm sure he had a few things to learn when doing so.
Not to take away from an obviously intelligent individual.
It's interesting to observe how programmers and other similar intellectual workers prostrate themselves in their own specific way when referring to someone of high status in their field.
Having followed Carmack a bit over the years my guess is he built something from scratch himself in C++.
C++ may be an effective language for experienced users, but it's got quite the learning curve (beginning with how exactly DO I write a correct constructor in the presence of exceptions...). Every time I have to work on C++ code I dig out my Meyers book to make sure I'm not fucking something up. C is small enough that I don't have to perform the same ritual.
Is it possible to create a language that fixes what C gets wrong while keeping what C gets right without becoming C++? There have been a number of attempts and none seem to have stuck, except for Go (IMHO). Java tried, and it did not fail altogether, IMHO, but it comes with yet another set of problems, mainly a tendency to lure programmers into over-engineering their solutions (the same, IMHO, goes for C#, which is kind of a sweet language at it core, but that becomes very hard to see among to tangled mess that is the .Net framework).
It always takes time to learn something new. Especially the fundamentally different way of working between OO and Functional programming.
he apparently has lots of fun with languages, very curious what kind of server he is writing now.
He also spoke highly about Haskell before.
> thoroc @touristtam 12h12 hours ago > @ID_AA_Carmack what guided your choice of Racket vs Rust and Go? > Just curious. :)
I think we would be better off caring a little bit less about what language to use and a little bit more about what programs to write.
Oh, and just gonna put this out there: http://benchmarksgame.alioth.debian.org/u64q/compare.php?lan...
and Erlang is certainly a valid platform for servers, so as usual benchmarks are just benchmarks... would be interesting to see if typed racked made a difference in these tests -- although I'm not sure if performance is the main focus of typed racked (as opposed to just type safety).
And indeed, of the ten benchmarks, four of them are singlecore racket vs quadcore Go. Single core-comparison is much less dramatic, though Racket is still slower.
Sounds like Python.
Works great at the start, and then one day you wake up and realize you are running 50K ppl online at the same time MMO (Eve Online), your code cant take advantage of multi core CPUs = every game region (star system) starts to lag above ~500 people and there is nothing you can do about it.
You know what gets things done and makes things easy to maintain? Boring ass code. IF statements. FOR loops. I mostly use Perl today. It doesn't get in the way. But getting things done is not trendy. That's where we are today.
It's surprising that a philosophy that tries to promote simplicity also manages to come across as so elitist at the same time.
When you have a lot of wordy, boring code to maintain, you have to make coordinated changes in more similarly boring places. A human's brain can only keep that many lines of context. So it becomes easier to make a mistake.
I understand that abstraction astronautics can leave you with puzzling, convoluted, hard-to-maintain code full of leaky unintuitive abstractions. This problem is not unique to Lisp macros; languages like C++ and even Java are known to be widely used by perpetrators of the above-mentioned atrocities.
What makes code easier to maintain is clear separation of concerns and low impedance between code's abstractions and the subject area. This is, again, attainable in a number of languages (though expressive power and minimalism help make it even nicer), given the right mindset and skills. I suppose John Carmack possesses both.
I'm beginning to use a phrase that I'd rather deal with poorly written code than well planned architecture. Obviously by well planned architecture I'm referring to overly architected solutions.
You know, the ideal device is that which is not even there, but its function gets executed. This ideal is rarely attainable, but it's something to crave for.
On a side note... Uncle Bob is my hero.
The only problem I'm having with this tack is that it reveals all the technical debt at once, which produces an enormous amount of pain early on. My friends smirked at my woes today of trying to make a clickable button, which has to piece together stuff from the graphics layer, input events, text fields, and internal button state. An enormous variety of data, altogether, with the debt usually hidden from view at some level. It all makes sense, it's all decoupled, the lifetime of the state is automatically managed, any configuration you want will just be a matter of making the data for it. But making that first button is quite a headache.
http://www.erictimmons.com/node/18
I don't know if it qualifies for serious, I'd say challenging enough, but it was great to revisit with another university material.
Code may also be boring simply because it is unsurprising for someone familiar with the subject matter.
When you have a lot of wordy, boring code to maintain, you have to make coordinated changes in more similarly boring places. A human's brain can only keep that many lines of context. So it becomes easier to make a mistake.
A problem nicely summarized by Yaron Minsky (of Jane Street): "You can’t pay people enough to carefully debug boring boilerplate code. I’ve tried."
By the way, FOR loops invite off-by-one errors and worse. Use a combinator like map, or filter or foldr etc, to keep things boring.
map { $_ + 1 } (@list); sub sum_of_squared_pairs {
reduce { $a + $b } map { $_ * $_ } grep { $_ % 2 == 0 } @_
}
sub schwartzian_transform {
map { $_->[0] }
sort { $a->[1] <=> $b->[1] } # use numeric comparison
map { [$_, length $_] } # calculate the length of the string
@_
}http://docs.racket-lang.org/reference/for.html
eg. fizzbuzz using for, match:
-> (for ([i (range 1 16)])
(match (list (modulo i 3) (modulo i 5))
[(list 0 0) (displayln "fizzbuzz")]
[(list 0 _) (displayln "fizz")]
[(list _ 0) (displayln "buzz")]
[_ (displayln i)]))
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzzhttp://docs.racket-lang.org/reference/sequences.html?q=in-ra...
An in-range application can provide better performance for number iteration when it appears directly in a for clause.
-> (for ([i (in-range 1 16)])
(match (list (modulo i 3) (modulo i 5))
[(list 0 0) (displayln "fizzbuzz")]
[(list 0 _) (displayln "fizz")]
[(list _ 0) (displayln "buzz")]
[_ (displayln i)]))I don't think that's been true for a while. Boost went a long way towards making C++ much more productive, and now that's gone even further with C++11 and 14.
Things are improving in C++-land, but I'd still place it near last.
I do not think Perl is a pretty language, but I have come to appreciate how useful it is. If all you want is a smallish application (roughly, less than 1 KLOC), especially if you're only going to use it once or maybe a handful of times, no other language I have met can keep up.
And for the kind of problem I typically use Perl for - reading, say, a CSV file or an Excel spreadsheet, filtering the data according to some criterion, fetching and adding data from an external source, say, an LDAP directory or a relational database, then inserting the result into a database or emitting another CSV file - it is also surprisingly hard to beat Perl's runtime performance, especially its regex engine. I'm not saying it can't be done, but for a program you're essentially throwing away after a week or so, it's usually not worth the hassle.
I can only assume you have not seen 300+ deep stack traces in lasagna java programs. Or GWT.
Other than that, I don't see what else there is to say about this. 'Dropped some C++ for Racket server: may not scale but is more productive'. That's the most standard high-level vs. low-level dichotomy.
Well, the "Argument from Authority" is called out because of when it's misused (kinda how "experts are always wrong". No: those are only the times you remember), but it is a fundamental way of how social humans form opinions.
Wow, that's amazing: people form opinions in part based on how much they respect/trust someone. Consider my cynical views totally and irreversibly changed.
Then there are those times when it is taken too far: like 115 points on HN for a pithy message like "rewrote to another language".
What he is doing is thus interesting to this forum though maybe as you pointed, not news worthy.
But since when does everything has to be news worthy?
Let's all just use Forth, and implement washing machines as simply as:
: WASHER WASH SPIN RINSE SPIN ;Indentation or delimiter based languages are much easier for me to parse than lisps.
Brackets, yes, but not nearly as bad.
(print "hello")
vs print("hello")
So to the extent Lisp is paren-heavy, it's more a stylistic thing. Lisp programmers tend to chain up calls more.main = putStrLn "hello"
And that's just talking about syntax. The type system complicates matters further.
(-b + sqrt(b*b - 4*a*c)) / (2*a)
(/ (+ (- b) (sqrt (- (* b b) (* 4 a c)))) (* 2 a))
It does depend on your use case.Nobody in their right mind uses this stuff in production code.
It just overcomes objections. "Oh, if I start using Lisp, there is be a way to use infix, should I really need it". Ten years and six Lisp project later, you still haven't used the infix stuff; the situation never comes.
You sure about that? I thought the lispy approach was generally pragmatic - you use what you deem handy for your application. It this weren't the case, there would be little need for macros in the first place. I can very well imagine, say, a scientific or engineering application that would share a common infix parser for both user-provided expressions (in the UI, to be more friendly to non-lispers) and heavy math lifting in the source code.
{-(b) + {sqrt((b * b) - (4 * a * c)) / (2 * a)}}Yes, and the first line's use case depends on the language built-in operator precedence rules to reduce the number of parens.
If you are using math formulas as an example of minimal paren usage, go with APL and have even fewer since all operators are equal precedence and associate to the right.
If you really wanted to write the quadratic formula (or math formulas in general) you could use APL and use even fewer.
b fnegate b b f* 4 a c f* f* f- fsqrt f+ 2 a f* f/1.
(/ (+ (- b) (sqrt (- (* b b) (* 4 a c))))
(* 2 a))
2. (/ (+ (- b)
(sqrt (- (* b b) (* 4 a c))))
(* 2 a))
3. (/ (+ (- b)
(sqrt (- (* b b)
(* 4 a c))))
(* 2 a))
4. (/ (+ (- b)
(sqrt (- (* b
b)
(* 4
a
c))))
(* 2
a))
Now you have a sideways tree, revealing the structure of the expression, where it is immediately apparent what the operands are of the / and the + and so on.Infix turns into a mess breakfast when it's too long for one line.
For this particular expression, I'd probably go with variant (3) in production code. Compared to the beauty of (3), the original one-liner is basically a strawman. In terms of clarity of structure, it trumps the infix also.
This is actually a very important point that is overlooked by Lisp noobs. In real Lisp code, expressions are not written all out in one line, whereby the human reader must mentally match the parentheses. Even numeric expressions that might be one-liners in Fortran or C, are split across several lines to make at least the major constituents clear in relation to the major operator.
Indeed. If you want less parens, use Haskell or Forth.
Furthermore, Lisp uses zero parentheses for grouping in order to override precedence. These parentheses don't exist in Lisp.
In print(2/(2+4)), we actually have two kinds of parentheses, because two different grammar rules use the same token.
C has even more parentheses. The parentheses in for (;;) are not the same as those in 2/(2+4) which are not the same as those in (double) p, which are not the same as those in p(42).
Lisp has parentheses that do one darn thing in the read syntax---at least when they are not literal as in "(" or #\(.
Just don't expect anyone to all that interested when you start blubbering about it.
It's precisely the other way around: finicky syntax issues consume far less time in Lisp. This isn't just a surface thing—when syntax occupies a block of resident memory in your head, you have that much less capacity to spend on the problem at hand.
It takes a while to adjust to a more regular notation, but that's true of anything unfamiliar. And what you get in return is astonishing.
If you edit s-expressions as data structures using something like paredit you'll actually code very quickly, and it'll also be impossible to have unbalanced parens.
Say you have this (| = cursor): (a b |c d)
If you type ( you get balanced parens: (a b ()| c d)
If you press Ctrl+Right twice you slurp in c and d: (a b (c| d))
If you then press Alt+Up you get back to: (a b c| d)
As you can see, you manipulate code on the level of data structures instead of manually placing parentheses, and you are actually prevented from making unbalanced parens in paredit. You can likewise move through code in ways similar to moving by word or paragraph in vim vs moving by character, but I only showed basic editing above.
I won't downvote you because I understand your complaint. But the problem is that you are unaware that you are using the wrong mode of editing for s-expressions. :) It's like editing photo using a hex editor: possible, but very much suboptimal.
After a lot of refactoring by someone inexperienced in python, something was indented inside of a loop that should have been outside it.
8 hours work for de-denting one line of code.
Also, in C/C++/Java/C#/whatever code, you can run into the same kind of problem on a smaller scale when editing deeply nested blocks and expressions, especially when dealing with complex arithmetic/logic expressions.
(I basically only use Lisp when messing with Emacs, so I would not call myself a Lisp hacker, but when learning Lisp, the braces cease to be a problem after a month at most.)