29 ms·
In defense of complicated programming languages
- tinasabri 5y ago[flagged]
- nfoz 5y agoIn case anyone hasn't seen this most excellent talk on this topic, I highly recommend: Guy Steele - Growing a Language (OOPSLA '98) https://www.youtube.com/watch?v=lw6TaiXzHAE https://www.youtube.com/watch?v=lw6TaiXzHAE
- deleted 5y ago[deleted]
- erik_seaberg 5y agoA language with a short learning curve is like a toolbox that’s nearly empty. You quickly run out of ways it could help you. We should optimize for experts, because that’s where each of us is going to spend most of his career.
- continuational 5y agoThe toolbox analogy breaks down when you realize that every language feature interacts with every other language feature. So it's more like a toolbelt that you have to wear. Hopefully, the tools aren't so plentyful and heavy that you spend all your energy dragging it along!
- verdagon 5y agoIs it possible to optimize too much for experts, and sacrifice learning curve too much?
- erik_seaberg 5y agoIf you can’t retain any or the project is short-term, I suppose. Probably nobody could learn a new language just for a hackathon.
- pjmlp 5y agoThen they are quite bad developers, because that is exactly what a team of ours did in a two day hackacton. Some learned C++ on the Arduino, some went with TypeScript and Angular, others with JavaScript and AWS Lambdas, together we got a robot arm to pick and drop pieces with a Web dashboard and remote control, talking with each other via the "cloud". Naturally all of them had several years of coding experience, but in other languages.
- tialaramex 5y agoIt's definitely going to vary according to your familiarity with other languages in the family. I came into a C# shop late last year from never touching C# before and was writing more or less idiomatic C# very quickly, but I've worked with lots of semi-colon languages so this is mostly familiar territory. On the other hand if you've never seen a Lisp before, ten years of C++ and VisualBasic won't prepare you to get anything much done in Scheme. Your reflexes are all wrong, and that's going to take some unwinding before you're productive. Also, people will hate it if you oblige them to use language A they don't know and which is poorly suited to the problem when they know language B that's well suited. Even if you've got a sane business rationale (e.g. bus factor, they're the only person who knows B in your organisation) they're going to spend a lot of time moaning about how terrible it is at this job they could do better. I do not like C++ but I'm immediately dubious about whether I'd rather try to control a robot arm from Javascript. Is there an option where I just have my foot surgically removed by people who know what they're doing? I guess maybe if the robot manages most of this itself and I'm really only overseeing it the Javascript is less awful, but if there's an actual real time control loop I feel like I'm very much between a rock and a hard place.
- pjmlp 5y agoIt was an hackton, so all of that was throwaway code anyway.
- TheMonarchist 5y agoC++ before 2011 springs to mind. From "Direction for ISO C++"[1]: "C++ is expert-friendly, but it cannot be just expert-friendly without losing important streams of new talent. This was the case before C++11 and C++11 reversed that negative trend." [1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2000r3.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p200...
- shadowofneptune 5y agoI do rather wish C++ 11 was a blank slate for that reason. Not really, as that'd kill C++, but there's so much good about C++ that is held back by its backwards compatibility with C and the dark ages of pre-11 C++. Data types and features are intended as best practice, but it's stuffed away in libraries since it can't replace the core of the language.
- Animats 5y agoC++ evolution since Rust came along has been amusing. Finally, the C++ designers take safety seriously, now that there's a competitive threat. Until a decade ago, they didn't. I used to argue with some of the committee members over that. The trouble is, C++ does safety by using templates to paper over the underlying C memory model. This never quite works. The mold always seeps through the wallpaper. Raw pointers are needed for too many APIs.
- Jensson 5y agoLanguages don't get popular unless they are very easy to learn, so no language popular today almost surely is biased in favor of learning curve and against complexity. We probably need some big industrywide intervention to create the optimal level of complexity in languages as I doubt even C++ is too complex to be optimal if you consider that you work 40 years in a career. It would work by just having a couple of standard languages so developers don't need to learn so many languages, then they spend a lot of time learning those until they are fluent and then they don't have to learn anything new about programming languages for the rest of their lives, very efficient.
- TheMonarchist 5y ago> It would work by just having a couple of standard languages so developers don't need to learn so many languages, then they spend a lot of time learning those until they are fluent and then they don't have to learn anything new about programming languages for the rest of their lives, very efficient. Programming methodology continues to evolve and languages need to address it to stay relevant.
- MathMonkeyMan 5y agoYes, as the creator of C++ has said [1] before. Personally, I'd also distinguish between "complicated over time" and "complicated by default." For example, Clojure has a minimal syntax and instead uses a large vocabulary of terse primitive procedures. If you don't know the primitives, it's "complicated." A different example is Rust, which has many features expressed in syntax. If you haven't learned all of the syntax, it's "complicated." Compare these with C++, which began as a small set of extensions to a stronger-typed C, but has gradually grown into a family of sub-languages, each added for a particular purpose, and all interacting with each other (sometimes beautifully, other times horribly -- knowing the difference is "complicated"). [1]: https://blog.codinghorror.com/the-problem-with-c/ https://blog.codinghorror.com/the-problem-with-c/
- BigJono 5y agoI don't think so, if you assume that learning is a linear thing and at the end of it you improve as a dev. But the problem is that learning isn't one curve, it's a bunch of them and most of them lead to dead ends or even turn backwards after a while. If you bloat out a language, what happens is that some subset of devs (like, maybe 10%) write really great code and have all the tools they'll ever need to do so. And the other 90% learn a chaotic mix of good and bad practices from each other, without the ability to properly distinguish them, and eventually reach some local maxima amongst themselves of overcomplicated "average" code that's shittier than I imagine it would be if they just kept the language simple.
- lmm 5y agoI certainly doubt any extant language actually does it, and also fundamentally there may just not be so much that's worth building into a general-purpose language. The most extreme examples I can think of are something like Haskell (which takes, what, a weekend to be able to write code in?) or maybe APL (which takes, what, maybe two months?). A language that was truly expert-oriented might take as long to learn as human languages do, or longer - certainly, for something you use your whole career, that much up-front effort would be worthwhile. But are there even enough distinct general-purpose constructs to fill that much time?
- iopq 5y agoTry learning Rust, then you reach this point https://stackoverflow.com/questions/39558633/higher-rank-lifetimes-and-generics-not-playing-nicely https://stackoverflow.com/questions/39558633/higher-rank-lif... I still don't understand what higher rank lifetime bound means and this affects whether I can write code that actually compiles
- lmm 5y agoWhen I was writing my comment I thought about Scala, where I was certainly learning useful new techniques 7 years into using the language, but that wasn't really about learning new parts of the language. I think Rust has picked an overly specific way to represent lifetimes, that makes them more of a special case than they should be. But maybe that distinction doesn't actually matter. (Higher rank lifetime bounds are like higher rank types, it might be easier to understand those first and then understand Rust's weird special case version of them afterwards)
- pornel 5y agoRust is in this weird place, because it needs to be palatable to C/C++ programmers. C has pointers and a vague notion of their lifetimes, but barely any type system to speak of. That's the lens through which Rust needs to present the problem.
- yxhuvud 5y agoYes, if nothing else because the problems that are solved shifts over time, as do preferred solutions. So if it is too optimized, there is a risk of churn.
- gcanyon 5y agoThere are certainly languages that test whether this is possible. J comes to mind: https://www.jsoftware.com/#/README https://www.jsoftware.com/#/README Here's something like the tenth or fifteenth chunk of code I wrote in J. It solves a programming puzzle. I doubt people who have mastered J would call it well-written, but it solves the problem. list=:_9]\33 30 10 _6 18 _7 _11 23 _6 16 _19 9 _26 _8 _19 _8 _21 _14 17 12 _14 31 _30 13 _13 19 16 _6 _11 1 17 _12 _4 _7 14 _21 18 _31 34 _22 17 _19 20 24 6 33 _18 17 _15 31 _5 3 27 _3 _18 _20 _18 31 6 4 _2 _12 24 27 14 4 _29 _3 5 _29 8 _12 _15 _7 _23 23 _9 _8 6 8 _12 33 _23 _19 _4 _8 _7 11 _12 31 _20 19 _15 _30 11 32 7 14 _5 _23 18 _32 _2 _31 _7 8 24 16 32 _4 _10 _14 _6 _1 0 23 23 25 0 _23 22 12 28 _27 15 4 _30 _13 _16 _3 _3 _32 _3 27 _31 22 1 26 4 _2 _13 26 17 14 _9 _18 3 _20 _27 _32 _11 27 13 _17 33 _7 19 _32 13 _31 _2 _24 _31 27 _31 _29 15 2 29 _15 33 _18 _23 15 28 0 30 _4 12 _32 _3 34 27 _25 _18 26 1 34 26 _21 _31 _10 _13 _30 _17 _12 _26 31 23 _31 _19 21 _17 _10 2 _23 23 _3 6 0 _3 _32 0 _10 _25 14 _19 9 14 _27 20 15 _5 _27 18 11 _6 24 7 _17 26 20 _31 _25 _25 4 _16 30 33 23 _4 _4 23 sumOfRows =: ([: +/"1 [: |: ] \* [: |: _1 + 2 \* [: #: [: i. 2 ^ #)"1 list rowSigns =: (;/@:,/@:>)"2 {|:(_1;_1 1;1) {~ (_1&<+0&<) sumOfRows candidates =:,/((_4]\4#"3 (_1 + 2 \* #:i.2^9) (\* &. |:)" 1 _ list) \* (>rowSigns)) theAnswers =: (] #~ [: (0&<@:+/@:(0&<) \* \*/@:(_1&<)) [: |: +/"2) candidates theSums =: +/"1 +/"1 theAnswers theBestAnswer =: ~. ((theSums = ] theBestSum =: <./ theSums) # theAnswers) In case anyone wants an explanation: https://gcanyon.wordpress.com/2009/10/30/a-solution-to-einavs-programming-puzzle/ https://gcanyon.wordpress.com/2009/10/30/a-solution-to-einav...
- 62951413 5y agoHaskell comes to mind. In all seriousness, not really. Learning curve doesn't matter for a language that we'll pay your bills for the next twenty years. And once you fully internalize a JVM/.NET-level platform or Scala/C++-level language a lot of that will be reusable in learning others.
- lgessler 5y agoAre you talking about the languages themselves, or the languages plus their ecosystems (of libraries, design idioms, etc.)? Because if you're just talking about the PL itself, I'd really disagree
- jimbob45 5y agoI don’t disagree but there’s also needless confusion brought on by syntax like the C++ pure virtual function syntax (=0;) that encourages mental models that don’t map 1:1 with what’s really going on.
- friedman23 5y agoExactly, I never how being able to learn a tool in a couple hours was something that made a programming language desirable to use. This is our profession, something we will be doing for a large period of our lives, choose the tool that results in the best output not the tool you can learn in an afternoon!
- valenterry 5y ago> A language with a short learning curve is like a toolbox that’s nearly empty. You quickly run out of ways it could help you. Very quotable! That's why I like it when languages allow you to start writing simple code and gradually make it more complex. Haskell for example is not like that. Python does better here. I think Scala is one of the best languages in that regard.
- dwohnitmok 5y ago> Haskell for example is not like that. Python does better here. I think Scala is one of the best languages in that regard. This seems ripe for getting a lot of passionate anecdotes out of the woodwork.
- dwohnitmok 5y agoHa or not. Looks like I was wrong.
- valenterry 5y agoNot enough attention maybe? :) Also, I like Haskell. It's just that the learning curve is much steeper at the beginning. This also has an advantage in that you will rather find experienced people in a project and don't have to deal with different styles within a project. The drawback is that it's harder to learn while being productive at the same time.
- cttet 5y agoLearning curve has two dimensions, a short and steep learning curve can actually achieve a lot. And that's why we call it a curve instead of "learning time" or "learning content", which are two different dimensions.
- novok 5y agoOne trend with complicated languages is poor scalability although. They don’t compile fast , tend to have slow iteration speeds and don’t scale with large teams or codebases well. You see this with c++ , rust, haskell, scala and swift.
- adwn 5y agoI'm curious to hear where you've seen Rust not scaling to large teams or codebases?
- travv0 5y agoI'd also be interested in a Haskell example.
- JoelMcCracken 5y agoGenerally this problem is because someone went crazy with template haskell or generics
- travv0 5y agoWhat problem? I'm looking for an example of where poor scalability has been a problem in a Haskell codebase.
- novok 5y agoGenerate 1 million lines of stupid repetitive code that varies slightly with a 100 line script and you'll see it happen quickly. Same issues with swift and even kotlin to some level. I don't have specific experience but I've run into it with other people who use both languages. My personal experience is swift. If 1 million lines sound crazy to you, you just need 200 engineers working on one project for a year or two.
- oaiey 5y agoI think Excel shows us that you can do a lot with a beginner friendly toolbox.
- dragonsky 5y agoYour point is well made, but in the case of Excel, the real question is should you do a lot with it?
- dragonsky 5y agoI would assume that if you have a toolbox with only a small number of tools, you would spend some of your time using that set of tools to make other tools that extend your abilities. I know that many developers in earlier times, before the internet, when programming languages were more limited and access to library repositories was not possible most experienced programmers built up their own libraries of functions that they would use and add to as required. These days, we still have these extensions to the languages, but they are shared in repos and are called shared libraries or frameworks.
- wruza 5y agoif you have a toolbox with only a small number of tools, you would spend some of your time using that set of tools to make other tools that extend your abilities There is a big issue. We are much worse than that. We iterate through workshops (even the ones we built ourselves), and also our products grow out of them — they never leave a workshop they were done in. As a result, when you come to a new place, it itself is unlike anything in your previous workshops, and the product itself is unlike anything you could use your previous toolkits on. Doesn’t really matter how easy it is to bring all your toolboxes with you, unless it’s a new empty place. That’s why agreeing on a rich-from-the-start workshop is important.
- lerno 5y agoHow does a short learning curve necessarily correlate to a "nearly empty" toolbox? That seems like a fallacy to me. Ruby is fairly easy to learn. Does that mean it has a nearly empty toolbox? No it doesn't. A language with a GC is easier to learn than one without a GC. Does the one with a GC have less in the toolbox? What if it also allows opting out of GC? ObjC is considered a hard language to learn, esp for people used to C++ and Java. Does this come from it having more tools in the toolbox? "A language with a short learning curve is like a toolbox that’s nearly empty" is a nice quote, but it also objectively seems to be wrong.
- yxhuvud 5y ago> Ruby is fairly easy to learn No, its not. Ruby as a language is about as complex as they come. It is easy to get to a productive state though, but that is not the same thing as having learned the language. Length of learning curve and accessibility are vastly different things.
- lerno 5y agoGetting productive easily is the pretty much the definition of not having a steep learning curve. So I have difficulties making sense of your argument.
- foxfluff 5y agoyxhuvud referred to length of the learning curve, not slope of the learning curve. Even if getting started is easy (no steep slope), mastery can take long.
- KptMarchewa 5y agoPython is the same. It's easy to write simple code, but once you get deep enough, the skeletons come out of closet.
- TrackerFF 5y agoProgramming languages are not unique to programmers anymore, and not all users will ever become experts. These days, programming is being thought to more pupils and students than ever, because languages like Python has made it very accessible and easy to learn. The fact that a non-CS/IT person who has never written a code in their lives, can learn the basics with languages like Python, and make tools which increases productivity in just mere weeks, is amazing. I know this, because I've witnessed it multiple times at work. That would almost certainly have never been the case, had we only had languages with steep learning curves. Imagine if someone wanted to make a web-scraper in C, and some program that act on the scraped data. In python, that's basically under 20 lines of code...in C? Most likely hundreds.
- dgb23 5y agoI fully agree with this. I think we're in the middle of a paradigm shift in regards to programming as more and more people enter the field or use programming as an auxiliary skill. Like with writing/reading and math there was a time where only experts would do these things. There is still quite a substantial difference between a seasoned literary scholar and the average person, but many have access to this skill now and the fundamentals have become normal. With programming I assume the same will happen. The fundamentals are simple and there are many ways, technological and cultural, to learn and use this skill. Here's a list of programming types: Web development, systems programming, game engines, data analysis, application/UI scripting, scientific computing, spreadsheets... I think we have to acknowledge and welcome this change and the people who will newly access this beautiful craft, while at the same time being mindful about what that means for professional identity and assumptions around that issue.
- yxhuvud 5y agoAt the same time, a language with built-in abstractions that are not fitting the problem at hand will force its users to spend time working around the bad abstractions, which will be messier than not having the abstractions in the first place. More churn can definitely be expected in a complex language.
- kaba0 5y agoWhat do you have in mind? I think the language providing an abstraction doesn’t mean in most cases that it has to be used — if classes are not a good fit for this specific thing, just don’t use them. So that would still boil down to inexperienced developers not using proper abstractions - which can happen (with smaller blast radius) in less expressive languages as well.
- preseinger 5y agoMost software is written and maintained by non-experts. Consequently you should optimize for time-to-onboard. Good tools are intuitive and easy to master; a hammer is basically better than a scanning electron microscope.
- Nevermark 5y ago> So, with disadvantages and advantages to the complexity of modern programming languages, what should one conclude? > The only resolution is for us as professionals to use our judgement. Or the third option: create the language with the simplest implementation of all necessary complexity. Unfortunately, famously, tragically, perfect languages attempted so far are examples of what not to do. The best ones are wonderfully unique examples of what not to do! I know because I have created more than several.
- Drblessing 5y agoA succinct and level-headed assessment of the programming language landscape. Agree that beginners need to struggle with unwieldy personal projects before " getting" typing and classes. "The idea is that you can't understand a solution without understanding the problem it solves," great quote! "But mostly, software is bounded by its creation process: Programmers have limited time to create, and especially limited time to maintain, code." Software is this weird commodity with no marginal cost but some "complexity" cost. Also, I remember taking a theory of the mind course and learned how people whose native language didn't have words for things like other people's minds or consciousness couldn't solve tests on those topics IIRC. Humans, in general, needed these words in our vocab to reason about these things. Just as adding words in our language helped us reason about higher-order concepts, these programming words and features allow us to reason about our code better. Furthermore, words in our language grow organically, just like these programming concepts.
- thaumasiotes 5y ago> Humans, in general, needed these words in our vocab to reason about these things. Just as adding words in our language helped us reason about higher-order concepts Except that words for concepts nobody's ever bothered to consider don't just appear in the language. That can only happen when somebody tries to think about the topic and is forced into making up some new words.
- tsimionescu 5y ago> Also, I remember taking a theory of the mind course and learned how people whose native language didn't have words for things like other people's minds or consciousness couldn't solve tests on those topics IIRC. Given that most animals can reason about other animals as agents with intentions, I'm not sure what people have been unable to answer. This also sounds a bit longer the discredited setting version of the Sappir-Whorf hypothesis (linguistic determinism).
- weavejester 5y ago"Classes would still exist, but as implicit patterns." Classes are not a design inevitability, but just one way of managing state. Languages that mostly avoid mutable state don't tend to have object systems, for instance.
- jakobnissen 5y agoRight, that's true. I think structs are inevitable, and classes is the way to get structs in Python. But yes, the entire OOP-classes with namspaced methods and "self", that's not inevitable
- pjmlp 5y agoIn a very simplified way, classes are extensible modules. That has always been in trend in most languages, first one gets modularity, then eventually they outgrown now being able to have generic modules, and eventually they land into something that is for all pratical purposes OOP (there are many ways to skin a cat).
- weavejester 5y agoI'm not even sure structs are inevitable. You could write a language around open sets of key/value pairs, for example.
- pjmlp 5y agoType classes and ML functors are also a way to do polymorphism and dynamic dispatch on data structures. So which languages are left without object systems?
- cttet 5y agoTo be more concise classes != object systems != polymorphism and dynamic dispatch on data structures The difference between them are important to some people. And that's why they will argue for that.
- 5y ago
- quirino 5y ago> In video game design there is a saying: Show locked doors before you show a key This is something I've tried putting into words many times. I'll try to solve a problem and get to know its challenges deeply. Then a tool is introduced that brings it all together. In these cases, I seem to quickly get a full grasp of the operation and essence of the tool. I wish education was based around this principle. A bit like what Paul Lockhart advocated for in "A Mathematician's Lament" (https://www.maa.org/external_archive/devlin/LockhartsLament.pdf https://www.maa.org/external_archive/devlin/LockhartsLament....)
- raverbashing 5y agoYes, this is one of my pet peeves as well. And what I think it's also important: don't ask for the key if the door doesn't need to be opened. The examples on the text about Python and OOO are on point. Yes, people would reinvent classes if they needed, but the great thing about classes (and type annotations) are that they're optional Compare with Java where you need a 'static void main' method inside a class just to begin. Why? Not even C++ requires that. Do help them keep in their lanes but keep simple things simple.
- fendy3002 5y ago> Java where you need a 'static void main' method inside a class just to begin C# too, but they remove the necessities to use static main for entrypoint, starting from C#9
- Banana699 5y agoThe sheer irony is that "lite" object systems like python and ruby are actually purer and more faithful to the ideals of OOP (as envisioned by Alan Kay and those with him and before him) than Java can ever be, with its ugly and unnecessary seperation between classes and primitives, a completely irrelevant distraction that is primarily a VM optimization detail which only compilers and other bytecode producers or consumers should have known or cared about. In python, nearly everything is a PyObject, data, code, source code files (which are just modules, which are just objects). It's highly misleading to name the things you get by calling a class objects, it implies this is somehow special, as if dicts and lists and ints, and classes themselves for crying out loud, aren't objects as well. This is why I cringe so much when people associate OOP with Java bloat, the language is just unimaginably badly designed, this has nothing to do with OOP. You don't even have to be dynamic like Python and Ruby to be a good OOP system either, although that is a particularly low-friction path pioneered by smalltalk and lisp, but languages like Scala and Kotlin prove you can be highly static, highly OOP, and beautiful to read and write without the sheer amount of paperwork Java heaps on you.
- anonymoushn 5y ago"Not having a borrow checker" seems like a noncentral example of the value of simplicity. "Not having a separate language for writing macros" seems pretty good.
- travisgriggs 5y agoI cut my programming teeth on Fortran, C, and Smalltalk, all semi coincidentally in my early formative years of programming (well there was also a pile of Lotus123 macros where I discovered that 640K was not enough (thanks a lot Gates) and invented something that years later I would realize was a swap space). Fortran seemed easy, C was similar, but my mentor wanted to impress me using strtok() in the middle of already existing strings to cut them into words. And like the author, I had my “uh… what?!?!” moments climbing the Smalltalk curve. Smalltalk was transformative for me. Unlike the author’s experience, I learned an object oriented philosophy in a pretty thoroughbred environment. The best way to learn a second spoken language is to immerse yourself in it. Wanna learn Norwegian well? Go live in Norway for two years. Unfortunately, while the hype around Smalltalk and some of its other peers rose, it forced others to “add/borrow” OOP into their philosophies. Classes were not the heart of OO in the Smalltalk-verse. The root proto class in many implementations was called Behavior. The whole gig in Smalltalk was binding behavior to data. Figure out where a good cohesive boundary for data that glumps together well and dress it up with behavior. You then excited your objects to, well, uh, behave. Or in the lingua Franca, you sent messages to them and they always responded with something. And that was pretty much the whole schtick. I found it a very useful system for modeling things around for me. More than any language since, I found I anthroporhized these behaviors a lot. Algorithm design was often a sort of “if I assigned different people in a room to represent different pieces of state, what would they say to each other to get the job done.” This is where my take deviates from the article. What was liberating about this, was that they kept it simple and stuck to this. In Smalltalk you might ask, well, what’s a class? It’s an object. But in most other OO systems, something happens here. Usualky, first class classes don’t exist. Or they do kinda. But often, it’s another area of the language you have to learn to specify behavior taxonomies. It’s like two different languages. How do you create an instance of a class. In Smalltalk, you sent a message to it. Because that’s what you did. You sent friggin messages! But in just about every other OO system, you now get to learn about constructors. Are they like messages/functions? Kinda. But they’re different. Do you express and invoke them like messages? See “kinda.” Separate sub language count now equals three. What about math? Gotta do that the way you learned how to do it in school. Precedence rules. But in Smalltalk, you sent a message. Meta programming? Send more messages. Control flow? Send messages. Looping? Send messages. Functional style collection traversal? Send messages. This isn’t meant to be a Smalltalk love fest. I moved on 10 years ago. But what frustrates me is that people refer to Algol derived languages as object oriented. Most of them aren’t. They’re object-additive. And functional-additive. They’re 10s of language ideas and syntaxes balled up in one, little bits of syntax competing for contextual disambiguation. They’re complicated for all the same reasons that while Spanglish is appealing to a wide body of English and Spanish speakers, you’d go nuts trying to put down a formal definition of how to speak it. OO isn’t why languages are complicated.
- dwohnitmok 5y agoThe crucial crux of this is whether the complexity is worth its weight. Different programmers will disagree, not least of which because this is tightly bound to how you prefer to think about programming. Moreover, what seems complex to one person might seem entirely straightforward to another. However, at the end of the day my personal worry is that the central thesis of the article is often inverted. A complicated programming language might not tame complexity within itself, rather it may instead breed even more complexity in its community and the code that is written in it. That complexity spirals ever more outward as new features grow that attempt to tame the complexity, but only add to the growing morass. This is not necessarily true, but I've seen it happen often enough that I'm very wary of how new features in a programming language interact with each other.
- nine_k 5y agoInterestingly, the strongest bouts of architecture astronautics in the Java ecosystem occurred when the language was simple: lacked generics, functional features, etc. It was the time of EJBs and other such J2EE stuff. I'd say that feature cohesion is important: in Java, the new(er) features blended into the language without creating incongruities and footguns. In C++, it was not as smooth, though. Another, and maybe more important factor, is the prevailing tastes in the community. PHP 8 is more complex than PHP 4, but the community attitude changed, many aspects of the stdlib and key frameworks evolved, and now PHP mostly shook off the stigma of being a cluster of antipatterns.
- iopq 5y agodef bark(dog_dict): print("WOOF!" if dog_dict["weight_kg"] > 25 else "Woof") rex = {"name": "Rex", "weight_kg": 35} This code is actually better, but it would even be better with structs and traits https://gist.github.com/rust-play/ceb5a292a22e55e27d56a83253fe74a4 https://gist.github.com/rust-play/ceb5a292a22e55e27d56a83253... We separate the concept of a Dog, the concept of something that barks, and the actual implementation in this case We also don't immediately print it, but just return a slice so you can print it later or pass it to another function It's a bit longer than the class example, but conceptually cleaner because multiple structs can implement the trait, some of them without a weight and of course I'm only going to print things in my main, the interface only returns a slice which can be passed to other functions
- ncmncm 5y agoMissing the point. If you read just a little farther, you get that extra apparatus has a purpose that is opaque to beginners, that just adds confusion.
- iopq 5y agoI'm responding to > And so they would have accidentally re-introduced classes, only this time the existence of classes would have been implicit in the code, and their behaviour ad hoc defined, their invariants spread all over the source files, and with no language-level tooling or introspection to help the programmer. Classes would still exist, but as implicit patterns. You don't need to do this with classes, my design is better than the class design because it's more flexible
- marcos100 5y agoFlexibility usually has a cost. It's not better or worse.
- ncmncm 5y agoCorrect! When the language provides apparatus to do the thing, everybody doing the thing is incentivized do it the same way, making libraries implicitly compatible. Cobbling things together yourself (which you can always do: these languages are Turing-complete) you are unlikely to do it compatibly with what anybody else does. This might be why Lisp never developed an ecosystem. Everybody can make their own pile of macros to customize the language for their use, with no standard interfaces that can be composed.
- WalterBright 5y agoOne difficult thing to accept in programming language design is that what mathematically is simple, consistent, and straightforward is not simple, consistent, or straightforward to people. For example, a simple, consistent, and straightforward expression syntax would be RPN (Reverse Polish Notation). But humans dislike, and much prefer infix with its complicated operator precedences. The real trick to programming language design is finding those constructs that are simple, consistent, and straightforward for users.
- teataster 5y agoSome humans dislike RPN. I am yet to find whether they really dislike or just find it unfamiliar. I am convinced that unfamiliar gets conflated with unintuitive and hard all the time.
- tluyben2 5y agoI think this is the takeaway as well; I prefer RPN (and I can read and I like k which is considered 'unreadable/readonly' and Lisp which is also apparently 'hard to read') because I am used to writing a lot of forth(likes); I like discovery while programming and it is quite trivial to stuff in a forth into anything, even when no-one did it before. For instance, 10 years ago, to speed up Xamarin (which was compile/run and quite slow at that), I sped up development by adding a Forth into C# so I could rapidly discover and prototype on my device without having to compile. And I have done that for the past 30 years, starting on my 80s homecomputer to avoid having to type hex codes and risk more crashing during discovering what I wanted to make.
- IshKebab 5y agoI agree with your general principle but I do think infix notation is still better because so many equations are a tree of binary operators. Look at how binary trees are drawn - the nodes are in the middle of their children. It just makes sense for binary operators to have their operands on either side. Otherwise you end up having to maintain some kind of mental stack which is just a bit mentally taxing.
- WalterBright 5y agoI remember first encountering classes. I simply could not understand what they were from reading the documentation. Later, I picked op Bjarne's C++ book, read it, and could not figure out what classes were, either. Finally, I obtained a copy of cfront, which translated C++ to C. I typed in some class code, compiled it, and looked at the emitted C code. There was the extra double-secret hidden 'this' parameter. Ding! The light finally went on. Years later, Java appears. I couldn't figure that out, either. I thought those variables were value types. Finally, I realized that they were reference types, as they didn't need a *. I sure felt stupid. Anyhow, I essentially have a hard time learning how languages work without looking at the assembler coming out of the compiler. I learn languages from the bottom up, but I've never seen tutorials written that way.
- schlupa 5y agoYeah, I also always have the necessity to look what the compiler does with the code you through at it.
- sanxiyn 5y agoYou've never seen tutorials written that way because roughly nobody but you learns programming languages from the bottom up. There is just no demand. By the way, where can I read a D tutorial from the bottom up?
- WalterBright 5y agoI just added a -vasm switch to the dmd D compiler so you can learn it from the bottom up! https://news.ycombinator.com/item?id=30058418 https://news.ycombinator.com/item?id=30058418 You're welcome!
- a9h74j 5y agoWalter, watch out. You want to talk about dumbing down? California is considering a new law in which every computer language must have a keyword 'quine' which prints 'quine' . And none of this looking under the hood stuff. That's doing your own research. Trust the computer science! :)
- Barrin92 5y ago>>"Focus on debugging your application rather than debugging your programming language knowledge." >Why would I want that? The entire point of modern language complexity is to reduce the amount of debugging needed for your application, because its complexity is properly managed by the language. The difference is that applications are always particular and specific to a problem. Moving mechanisms from the application towards the language, which unless domain-specific, is a general purpose tool, does not guarantee reduction in complexity. If a language restricts me from writing a program, the language says "what you want to do is so bad, we must eliminate it for the entire userbase of the language!". This is a very tall order. Very few restrictions are so universal in their application that they apply any program a user would want to write. The author posits the hypothetical that Zig's lack of manual memory management creates more runtime crashes, but it is just that, a hypothetical. It depends on the application and the use case, and the individual developers. And it comes for example at the cost of performance in a situation where the developer wants to manipulate memory manually and is willing to take the risk of introducing errors. Strict language features restrict the ability of developers to deal with problems as they see fit. It's a form of top-down design that assumes that general solutions are effective at addressing particular problems. One can argue for example that syntax-heavy languages are much more clear and uniform but they are also restrictive. Lisps give developers directly much more power, but may come at the price of providing fewer guarantees. Personally I'm not a fan of overbearing languages. Features and guarantees the languages provide have trade-offs. In some situations they may not be worth it and at the end of the day I have problems that a language designer cannot have anticipated because they're relevant to me, and I want the freedom to address them as I see fit. If a tool is inappropriately heavy-handed it turns from being useful into being restrictive, and it makes my job harder, not easier. A practical example for me is program correctness. I much prefer an extensible tool like clojure.spec, which lets me add guarantees as needed, over a very harsh type system built into the language. If a type system eliminates valid programs that I deem appropriate, it adds complexity for me. And a last point, I focus on restrictions in terms of 'complications' rather than features because one can always omit using a feature of a language, but has to abide by its restrictions.
- Asooka 5y agoGiven their example about classes and "don't show the key before showing the lock", it's ironic the writer pans languages aiming to be "simpler" without understanding the kind of complexity they're actually avoiding. Zig, Go, (and Java and C# and other not as sexy and modern examples) are avoiding C++'s complexity - features with complicated interactions between each other that can sink your program without you being aware at all. My favourite example is how the integer promotion rules make multiplication of unsigned shorts undefined behaviour, even though unsigned integral numbers have well-defined wrap-around arithmetic. Going by [1], we have the following rules: 1. Usual arithmetic conversions: The arguments of the following arithmetic operators undergo implicit conversions for the purpose of obtaining the common real type, which is the type in which the calculation is performed: (...) binary arithmetic: , /, %, +, -; (...) Both operands undergo integer promotions . 2. If int can represent the entire range of values of the original type (or the range of values of the original bit field), the value is converted to type int 3. (added after the above rules existed for the purposes of better optimizations) If the result of an arithmetic operation on two ints over- or underflows, that is Undefined Behaviour. 4. 0xFFFF 0xFFFF = 0xFFFE001 > INT_MAX 5. Therefore, two unsigned short values cannot be safely multiplied and must be explicitly cast to "unsigned int" each time. [1] https://en.cppreference.com/w/c/language/conversion https://en.cppreference.com/w/c/language/conversion
- matu3ba 5y agoThe problem with implicit wrap-around of unsigned integer is that it makes your program slower. The underlying hardware with 2s complement does not need to pay the cost of reserving the overflow space or shifting/masking it out. Further more, its more consistent if signed and unsigned behaving identical than having to look for the type with integer promotion rules of the number. If you prefer the current C/C++ way of less performance and inconsistency that is fine.
- Asooka 5y agoAnd now I see that HackerNews ate my multiplication symbols. What I meant to type is that unsigned short a = 0xFFFF; unsigned short b = a; unsigned short c = a * b; Is currently undefined behaviour on platforms where int has more bits than short (like x64 and arm) due to the interaction between the integer promotion rules and undefined integer overflow.
- jchw 5y agoI agree with almost everything about this article. I am also a known Go zealot. What gives? Well, I think the author underestimates just how much needs differ across different programs. Go excels with services because they are often written with a shared-nothing mindset for horizontal scalability. If you’re using S3, Redis, PostgreSQL and RabbitMQ for all of your persistence and coordination, it leaves only small bits for your service to be concerned about w.r.t. local data races, and they are mostly encapsulated into libraries, sometimes provided by the language, that can be aided with static checking. There is something in video games called minmaxing, which is where you maximize one attribute at the expense of all of the others. For me C++, and now Rust, feel like they are guilty of this with their weight on zero-cost abstractions. I am not against efficient code. It is super awesome to generate efficient JSON serialization code at compile time. In aggregate, even a few hundred cycles per request could be a big difference. But as many have already stated, the secret to zero cost abstractions is that it’s zero runtime cost. Just as reducing programming language complexity doesn’t remove it, but only moves it around, removing runtime cost doesn’t remove it either. And the problem here isn’t that compile time isn’t a better time than runtime; it’s the hidden costs that suck. Sure, maybe the compile times in Rust will improve, and maybe it’s not even that big of a deal. But every little feature the language has puts some additional stress on the ecosystem. The language server has to bear this load, for example. Everyone knows the downsides in Go’s approaches to code generation, but I actually think it’s kind of intriguing. go:generate is imperfect in almost every way, and yet it’s oddly practical. It doesn’t guarantee code is not stale, but clever codegen design can cause syntax errors when regenerating code is needed. But maybe most interestingly, gopls doesn’t need to care. The go compiler doesn’t need to care. The parser doesn’t need to care. As far as they are all concerned, the generated code is just more code. To me, this is clearly an approach that doesn’t suffer from minmaxing. Maybe it suffers from a dogmatic fetishized idea of simplicity, but I don’t think so: I think it was literally just meant to be the bare minimum to try to solve the most important parts of the problem, and at that it succeeds. I am not saying that Rust isn’t awesome. In fact, what I am saying is that I think a lot of smart people have fallen into the trap of thinking that Rust is the one true programming language simply because it’s such an alluring story. But, I think there’s more room. Formally verified C, Go, Rust and Zig will probably all co-exist for the foreseeable future, along with many other permutations of programming languages. Nobody is going to write a web browser in Go, or at least not anything to the scale of Servo or Chromium. But, if you wanted a language to write some servers in, well, hell, you could certainly do a lot worse than Go. I don’t want to go too into it, but I also think there is some overly optimistic viewpoints here. It is true that reducing language complexity will often move it elsewhere, but that does not mean that language features do not cause complexity that doesn’t exist otherwise. For example, the Rust borrow checker. Yes, I love it. It is not perfect. It allows only a subset of valid, correct code, and it’s excessively hard to write, for example, a correct doubly linked list in Rust. Does that mean it’s useless? No. But, in general, it’s not very hard to write a correct linked list. (It’s easier to write a subtly flawed one, but that’s neither here nor there. :) Thankfully, most people do not need to write a linked list implementation, but I do still think this stands as an interesting illustration nonetheless. And I am not suggesting that it’s a superior option at all, but if you are in a simple language like Go, it’s still possible to eat some cake and have it, too. gvisor’s checklock program is a pretty good example. Not perfect in almost any regard, but again, it represents a different set of tradeoffs. Rust frontloads an awful lot of complexity for cases that are not necessarily common for everyone. And that complexity, both in the toolchain and the resulting code, is a cost that gets paid repeatedly forever. It needs to have a good payoff. Systems programming and game developers have a lot to gain. Everyone else? I think it’s up for debate. May the best languages prosper. Ideally cooperatively.
- cttet 5y agoThe definition of "simple" and "complex" is very vague here. If we use Clojure's philosophy of simple, Python is by no means a simple language, even without classes. There are a lot of special syntax like `with` `as` `elif` `for .. else` and concepts such as `nonlocal`, not even mention generators, decorators and lots of fancy stuffs, although it is easy to learn... I don't agree with the author that static type makes things more complicated... Instead type make things much simpler and easier to reason about.. In the Python's example, the author indeed like to reason about static typed systems... And about classes, it is just a leaky abstraction legacy we have to deal with now.. "so they would have accidentally re-introduced classes" definitely no.. We can use structs, traits, interfaces or much better ways for abstraction than classes, which was introduced with ideas for inheritance.
- IshKebab 5y agoStatic types are definitely make the language more complicated. It will have a bigger specification and more complicated implementation. You could even argue it makes writing programs more complicated. But they definitely also make writing programs much much easier. Kind of like how algebra is more complicated than basic arithmetic, but good luck proving Pythagoras's theorem without algebra.
- nbabitskiy 5y ago>> good luck proving Pythagoras's theorem without algebra. https://avatars.mds.yandex.net/get-zen_doc/48747/pub_5c9e493ce3ee0900b3277686_5c9f110f111e6e00b2e6e93f/scale_1200 https://avatars.mds.yandex.net/get-zen_doc/48747/pub_5c9e493...
- IshKebab 5y agoI don't understand. That uses algebra.
- nbabitskiy 5y agoThe proof is on the left, and doesn't require algebra. You can use another picture for the right part, like this https://microexcel.ru/wp-content/uploads/2020/05/kvadrat-summy-1.png https://microexcel.ru/wp-content/uploads/2020/05/kvadrat-sum... (it also uses algebraic notation which can be ignored)
- kg 5y agoModern C# is way too complicated, and I really dislike that. On the other hand, as I've tested out the new features, I have to admit that most of them are good. Part of what makes this work is that wherever possible, they made the features compiler-only, which means I can use them without having to update my application to use a newer runtime or newer libraries. This means I don't have to worry that updating my code will break compatibility for existing users. The other key thing for me has been realizing that a significant portion of the new features enable me to replace old verbose/bad code with new concise code that has desirable properties - it's become easier to reduce duplication and easier to write efficient code that avoids allocations and better exploits the type system. Some simple examples: the addition of 'in' parameters which behave like 'ref' but are read-only, which enables the compiler to automatically pass values by-ref when appropriate - this means you can replace existing by-value arguments with by-ref arguments and not break any existing code. It's really great. they added 'ref' locals and 'ref' return values, which means you can do a clean and efficient mutable version of 'list[i]' like in C++ but without any of the semantic issues (storing the ref is explicit and the compiler prevents you from accidentally introducing memory safety issues.) generics were expanded to allow you to safely manipulate pointers, which means that high-performance code no longer has to use gross tricks and can now be type-safe. in modern releases you can now finally do arithmetic with generic types as well (though sadly this requires an updated runtime). The addition of tuple types bothered me a lot too until I realized that the tuples were silently updated to value types, which means writing obvious tuple-based code is actually highly efficient and I don't need to hand-write record types. the async/await features have some major downsides, but on the other hand the compiler and library design teams built in a bunch of really wise escape hatches to let you work around issues. The whole state machine can be customized to swap out all of the internals, you can define your own types with seamless 'await' support, and the compiler will (in release mode) aggressively turn the state machines into structs so there aren't any allocations. It's really nice and transitioning my code to it has been a huge improvement. linq is notorious for bad performance, but they made it possible to provide your own implementation of all the query operators so it was possible for me to define my own methods and make my linq queries not allocate at runtime. really nice (though it comes with its own tradeoffs).
- kreutzwj 5y ago
- roomey 5y agoI still don't get classes in python. For now I wrap my data objects as a json and use rabbitMQ to message the json to all the other running .py's I heard about async and want nothing to do with it thank you. I do understand the need to maintain a mental model of the code so I gave based everything on Sherlock Holmes novels.
- usrbinbash 5y ago>Encapsulation, modularization, abstraction - let's not pick nits about the precise meaning of these terms, they are all about the same thing, really: Managing complexity of your own code. The thing is, code complexity can be managed superbly without the concept of a class. Golang doesn't have classes. C doesn't have classes. But both have structs and they have functions taking a pointer to, or a struct of type T. (what OO calls a "method" for some reason). So we can have "objects" as in, custom datatypes, and we can have functions to act on them. And on top of that, we have modularization in libs and packages. So, why do we need more complicated languages? "Show a locked door before you show a key" indeed.
- eitland 5y ago> What more do we need? Good languages with good IDE support? I'm old enough that at some point assembly and C were my favourite languages and PHP was what I was most productive in and Python was also something I enjoy. These days no way I go back for new projects. After Java "clicked" for me and the introduction of Java generics shortly afterwards it became my favourite language and later TypeScript and C# had been added to that list. I'm not to dumb, but I prefer using my smarts to develop programs, to work together or even pair program with the language to mold something, not to babysit languages that cannot even help me with trivial mistakes.
- zelphirkalt 5y agoIs not the point, that a language with optional typing can help you out with trivial mistakes, if you give it sufficient information? Java makes (made?) you give all the info all the time, even when you do not need its help. Java holds your hand in an annoying way. TypeScript does not because you can gradually add types to your program, but is based on the shakier foundations of JS.
- dmurray 5y agoYes, I would agree that structs are the solution to the complexity the author describes. But Python doesn't have structs: if you don't learn about classes you will probably eventually organize some data using dictionaries or heterogeneous tuples. In another language you might introduce structs first (C and Go only have structs, C++ has both classes and structs but they are the same thing) but in Python you don't have that option - you can use data classes or named tuples but those already need most of the ceremony you introduce for dealing with classes.
- r34 5y agoWhat make it difficult for me very often are bad examples. The set of standard examples for introducing concepts of class, object, inheritance etc (animals, geometric figures, cars) makes things harder in some aspects in my opinion. That was at the beginning. Some time ago I was learning design patterns and again - after understanding the concept I usually understood how bad were the examples. I've never read a good explanation of SOLID principles.
- kstenerud 5y agoThere's a distinct difference between complexity and complication, which I think is what the author is looking to convey. Complexity is just inherent to the system you are building. The only way to decrease complexity is to do less. Hiding it only moves it somewhere else. There's a whole school of thought around the idea of reduced functionality, and in fact it's baked into the UNIX ethos of "do one thing well". Complication, on the other hand, is what I would call "unnecessary complexity" that gets added to a system as you bolt on more things to give it more potential, or to support legacy. We see this in a number of programming languages, most famously C++. Adding more capabilities to the language requires you to have more knowledge before you can effectively use it. Adding features to something not designed for it (cough Java) results in some very annoying complications. And THIS is where the call for simpler languages comes from. The misunderstanding between complexity and complication is what causes for example golang to be such an annoying language. They sought to reduce complication (a laudable goal), but conflated that with complexity and only managed to move it elsewhere (because that's all you can actually do with complexity). We see similar problems in data formats. JSON has lax standards and limited type support, which forces the complexity onto the user in the form of string serialization and base64 and all sorts of incompatible custom secondary codecs. Is the format itself simple? Sure! The spec fits on one page! Is it simple to use? Absolutely not! It's a minefield and a security nightmare. Data is complex, and any decent data format will have to be just complex enough to support the majority of use cases in a consistent fashion.
- kaba0 5y agoI generally agree with you (with the addition of it being often referred to as essential (which is non-reduceable) and accidental complexity=complication in your words). May I ask you why do you think Java is an example of adding features it was not designed to have? In my opinion, even with the original warts of the language, it is one of the few long-running languages that managed to withstand adding every feature and the kitchen sink, and additions are thoughtful and deliberately slow (late-movers advantage, it let’s other languages make mistakes with a feature first, avoiding bad ideas like async). Generics was added very cleanly to the language seeing the constraints of the time, lambdas are also more than good in my opinion (with the only wart being around checked exceptions, unfortunately). The new direction with algebraic datatypes (record, sealed classes) and pattern matching is also an example of a feature that was known forever (ML), but the general developer community got to like it only recently. it is only bad in the context of managed languages that can do better. It is a “necessary evil” in case of rust for example
- tomxor 5y agoI had a similar experience. As I grew more experienced I also found it peculiar how sometimes classes worked really well, and other times they were a terrible fit. Eventually I realised, as an abstraction they are far closer to high level patterns than rudimentary functions - but the fact that they are a very common pattern built into so many languages obscures that attribute from most people. > Classes would still exist, but as implicit patterns. Once you realise this, you also start to notice how often overused and misused classes are, because they seem to be the first thing many people reach for. Classes are not an inherently bad pattern, but that doesn't mean they work well for everything either. I think teaching them from the perspective of a "need" as the author suggests, would not only make their purpose clearer for beginners, but also prevent them being so misused.
- pron 5y agoAs someone who strongly dislikes complicated languages, it's obvious to me that it's a matter of personal preference; personal aesthetics, if you like. If the choice is between complexity in the language and elsewhere, often I'd rather it be elsewhere. But while that preference is entirely subjective, what isn't subjective is the distribution of that preference among programmers. I think that we can say with as much certainty as we can about these things that the answer is clear: the vast majority of programmers prefer simpler languages. So much so that while language simplicity is by no means a sufficient condition for high popularity, it seems that it's a necessary one. But I'll go further. My gut feeling, which is by no means even remotely scientific, is that those who prefer simpler languages outnumber those who prefer complicated ones 9:1. Moreover, my feeling is that the ratio is higher at the low end of programmer capability than at the higher end — and it makes sense, as more capable programmers can handle more complexity, so some — still a minority, but a larger one —prefer moving more of it to the language.
- christophilus 5y agoI don’t know. It seems to me the progression is “I like simple languages.” To “I like how expressive I can be. Look at this elegant one line program I wrote.” To “I like simple languages.” Anecdotally, as I’ve gained experience, I and most people I know have only grown in valuing simplicity. It’s one reason the the average Clojure developer is older.
- deleted 5y ago[deleted]
- kaba0 5y agoI’ve seen many of your comments (sorry, I’m not stalking you, just find both your work on Loom and your fresh take on some CS problems really interesting) regarding languages and would like to know how would your ideal language look like? I know that you are quite fond of Zig’s simplicity, especially the way they replaced many complex features of c++, rust by a simple constexpr feature. I would wager you also think of Java as a simple language, and I remember seeing Clojure as a positive example somewhere as well. You also seem to suggest that a “high level low level” language is not really possible (the trap c++ and rust falls into) due to low level details always seeping through, making refactors much slower. So my question is: how would the ideal low and high level language look like in your opinion? Regarding the high level languages, do you find java’s Valhalla plans good? I personally really like the semantic-only distinction of basically loss-of-identity, and loss-of-tearing, giving ample grounds for optimizations behind the scenes, and over time (in part thanks to some of your comments), I grown to really like the simplicity a language with simple classes and methods can bring.
- account-5 5y agoAs a non-professional and in essence beginner programmer who likes to learn about programming and writes simple to moderately complicated scripts I have to say I am currently in the mindset of not needing classes. In fact the first part of the article I was like: yeah no need for classes there, a function is way simpler. Now like I say I write fairly simple scripts, I mostly automate manual processes, but even after reading the article I'm still not sold on classes. I have to admit using dictionaries/associative arrays as the author showed and have often wondered over the difference between classes and objects. But I still don't see the problem. I known my lack of knowledge and understanding is showing here; I'm no expert and have never written any massive software. Can someone point me to an example where a class is more suitable than a function working on an object like an associative array? Genuine question from the ingnorant.
- marginalia_nu 5y agoIt's mostly a matter of scale. In some sense, classes are just "functions working on an object like an associative array", x.y(z) is a fancy way of writing y(x, z) and python even makes that explicit. The point is they're designed to keep those functions in the same place and not leaking all over the code, keep similar utility and data in the same place. If you are writing small scripts, it really doesn't matter. If have a million lines of code and thousands upon thousands of source files, any structure you can impose on it makes a big difference. That said, OOP is just one paradigm of imposing structure.
- _old_dude_ 5y agoThe two main advantages of using classes are: a class is also a type (if you have a typed language), a class is also a module, you group together values that makes sense together (the x and the y of a point) with the functions (methods) that interact with it. When you have a lot of codes flying around, you can add encapsulation (private/public thingy) so the user of a code does not see the implementation which helps to create libraries that can evolve independently from the applications using them. Also compared to an associative array, a class is more compact in memory (granted JavaScript runtimes see dictionaries as hidden classes).
- wwosik 5y ago
- tpoacher 5y ago> Show locked doors before you show a key This is a great pedagogical insight, expressed in a very nice way. Thank you for this goldnugget :)
- nimmer 5y agoThis is why I like https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax and Nim.
- matu3ba 5y agoI would like to bring up some counter-examples: - 1. Generators that can allocate prevent comptime-overapproximation of potential stack usage (https://github.com/ziglang/zig/issues/157#issuecomment-763952294 https://github.com/ziglang/zig/issues/157#issuecomment-76395...) or make analysis inside the compiler significant harder. - 2. There is no reason why static analysis must be part of the compiler, though its still an open research problem how to present lifetimes properly to the user (https://github.com/ziglang/zig/issues/782#issuecomment-1014955593 https://github.com/ziglang/zig/issues/782#issuecomment-10149...) - 3. Requiring static analysis to be inside the compiler pushes back on external static analysis. While this may be overall good to force upstreaming work and prevents monetarian incentive of introducing bugs as optimizations detectable by tool xyz, it reduces modularization incentive and extensibility for experimentation. - 4. Trying to encompass everything in static analysis has the same problem as the all-encompassing logic: Soundness can not be proven and the proof for soundness becomes more and more problematic the more rules one adds (slow and hard to reason which rule has been applied). And this does not even account human errors or the fact that a PL does not accurately implement the logic. - 5. The biggest problem of complicated languages is that they have no process to define what underlying logic (see point 4) the compiler should follow and "what is too complex". Somehow folks also forget about Gödels incompleteness theorem (you cant reason on everything in the compiler).
- ozim 5y ago> The problem with the example of Rex the Dog is that classes are not about being able to represent your dog. It's about something completely different. Encapsulation, modularization, abstraction - let's not pick nits about the precise meaning of these terms, they are all about the same thing, really: Managing complexity of your own code. Author is also missing a big part of explanation here. Real problem is that you won't have one dog, you will have hundreds of dogs with different attributes and you want to make them bark at each other. When you have to implement bunch of running dogs - then you hit encapsulation, modularization and abstraction. Those properties are not some kind of given especially in example presented, but for me question "how can I make 100s of dogs" comes naturally. So in the end author really misses Object vs Class distinction and I can see it in the writing. Author equates Object and Class where in reality Object is an instance of a Class in run-time, so you make "Rex" and "Lassie" dogs which are Objects in your program and can bark at each other. Classes cannot do anything as those are simply templates for creating Objects, you cannot do operations on a Class. So below sentence is simply wrong: > You have now defined a Dog class and can do operations with your dog by simply writing
- robalni 5y ago> The complexity of Rust's ownership model is not added to an otherwise simple program, it is merely the compiler being extremely pedantic about your code obeying rules it had to obey anyway. Not exactly. I remember when I learned Rust a few years ago (so maybe things are different today), sometimes the compiler didn't let me do things that should have been perfectly fine things to do. This forced me to write the code in a more complicated way than what should have been necessary. I think this often happens beacuse the compiler's rules don't always match reality. Like if I have a struct S that contains members X and Y, the compiler doesn't let me have two mutable references to that struct even if one of them only changes X and the other one Y. In reality there is no problem but compiler thinks there is a problem so it forces me to write more complicated code. I have had this almost exact problem in a program I was writing. The reason I could not just pass X to one function and Y to the other is that one of those functions I had to call was from a library that could only take an S. The solution was that I had to write a macro that extracted Y from S and call that macro every time I wanted to pass Y to a function.
- zozbot234 5y ago> the compiler doesn't let me have two mutable references to that struct even if one of them only changes X and the other one Y. The semantics of mutable references and other interface constructs must be independent from actual implementation, to allow for changes in the latter. So Rust is behaving as expected here. If the changes to X and Y are truly independent, you can have a function that returns separate mutable references to both ("splits" the struct). But if your library function takes an S, it might rely on the whole struct and then the changes are no longer truly independent.
- cowl 5y ago> then the changes are no longer truly independent. But the author of the code is telling you that they are independent. The author may be proved wrong if some future change accidentally triggers dependence but we as humans can have knowledge that the compiler can not have. The compiler sees a possibility of conflict and wants to protect you from yourself. That is a usability issue.
- dnautics 5y agoI would take issue with the zig vs go: go tries to make everything simple. Zig tries to make the simple things simple, but very much exposes the systems complexity. I would say zig is uncomplicated, but can embrace complexity.
- nmilo 5y agoOne thing that isn't often mentioned is that complicated programming languages nearly always come with complicated tooling. C++ has cmake, which is self-explanatory, and even cargo is pretty complicated. I'm still not sure what is a crate vs. a package, and the amount of times I've had to look up the bindgen tutorial, and the amount of steps involved, is too much. This isn't even to mention compile times, debug-mode executable speed, etc. This isn't the complexity moving from the source code to the tooling, this is complexity created in the tooling itself required to manage the complexity created by the language.
- blub 5y agoAnd they attract programmers which love complicated code. Of course they don’t actually call it complicated and in fact they see it as elegant and state of the art. People have figured this out about C++, but they’re still in denial about Rust. Notice how in the article the borrow checker is the best kind of feature which emerged to handle an existing problem. In reality the borrow checker is a hammer which forces all code to look like something the borrow checker can nail down. Rust is similar to C++ and it looks like it will be used outside low-level programming or systems programming and in those cases one can gladly give up e.g. manual memory management, obsessively avoiding copying, having to specify how wide an integer is and so on at least in parts of the code.
- naasking 5y ago> Over and over, every piece of documentation for the Go language markets it as "simple". This is a lie. Or rather, it's a half-truth that conveniently covers up the fact that, when you make something simple, you move complexity elsewhere. I'm not sure this is strictly true. This is true of essential complexity, but not true of accidental complexity. Some programming language abstractions introduce a lot of boilerplate and accidental complexity, so "simplifying" could just mean bringing the language more in line with a natural expression of a program.
- alkaloid 5y ago
- deleted 5y ago[deleted]
- geenat 5y agoPython modules are basically a singleton class. It's somewhat unique among languages (JS has this too). Makes it so you can "unit test" modules without actually using a Python Class. I see the Python Class as a way to get a "module within a module". Nice side effect of Python modules as singletons: The "self." is implicit to the scope of the module- This makes them a joy to write. In most other languages, yeah, you'll want some form of encapsulation so you can write tests. Type checking can cut down on the amount of tests you need to write, but you're continually paying for it with dev time. This is a decision that needs to be made depending on what the project is, whos working on it. If I'm on a team with a lot of new people who will try shoving data where it shouldn't go, yes, gonna force type checking and take the velocity hit.