Waaah, I don't get paid to use new shiny languages


  • I survived the hour long Uno hand

    https://medium.com/better-programming/modern-languages-suck-ad21cbc8a57c

    I'm only about halfway through it so far, but I think this guy is a JavaScript programmer at heart.

    Also, I found this pretty funny:

    The first language on our list with a modern null alternative! Rust doesn’t have a null or nil value, and Rust developers use the Option pattern instead.

    // The value returned is either a Some of type T, or None
    enum Option<T> {
        Some(T),
        None,
    }
    

    :sideways_owl:



  • The guy complains about the lack of built-in immutability in C# using one sentence (does not exist)

    And then says that Javascript has good libraries for immutable data. :wtf:



  • In C++, all references are nullable.

    Not really. You can't legally create a null reference in C++. :pendant:/🐠



  • @cvi Also, C# 8.0 let's you declare non-nullable reference types. Which makes a large portion of his complaint go away.


  • ♿ (Parody)

    Functions that do not mutate(change) any state are called pure and are significantly easier to test, and to reason about. When working with pure functions, we never have to worry about anything outside of the function. Just focus on just this one function that you’re working with and forget about everything else. You can probably imagine how much easier development becomes (in comparison to OOP, where an entire graph of objects has to be kept in mind).

    Also they can only rely on the data passed as parameters.


  • Banned

    I’m going to cover two of the most common language families in the world: languages descended from C, and languages descended from ML.

    Rust is a modern low-level language, initially designed as a replacement for C++.

    Language family: C.

    What a fucking idiot. First he introduces the most useless classification imaginable, and then he fucks it up! Rust is literally modified OCaml, grammar-wise. The guy has no fucking clue what he's talking about (in case it wasn't obvious from the very premise of the article itself).


  • BINNED

    @cvi said in Waaah, I don't get paid to use new shiny languages:

    In C++, all references are nullable.

    Not really. You can't legally create a null reference in C++. :pendant:/🐠

    “All”, “none”, what’s the difference really. 🐠


  • ♿ (Parody)

    @Gąska said in Waaah, I don't get paid to use new shiny languages:

    The guy has no fucking clue what he's talking about (in case it wasn't obvious from the very premise of the article itself).

    He kind of called it, though, in the first paragraph:

    Seeing such articles makes me cringe — their authors must have been outright lazy, inexperienced, and lacking any imagination.


  • Banned

    @izzion said in Waaah, I don't get paid to use new shiny languages:

    Also, I found this pretty funny:

    The first language on our list with a modern null alternative! Rust doesn’t have a null or nil value, and Rust developers use the Option pattern instead.

    // The value returned is either a Some of type T, or None
    enum Option<T> {
        Some(T),
        None,
    }
    

    :sideways_owl:

    In case you're not being ironic in your confusion, the important thing about option type is that it's part of type signature - the value can only be non-existent if it's explicitly marked as optional, and conversely, if it's not marked as optional, it's very definitely always existent. Very similar to non-nullable references that are all the rage in C# and Java nowadays, except with option type, it does that right thing by default - instead of opting out of every single input value being a ticking time bomb that can go missing when you least expect it, you have to opt-in - and when you opt-in, you have more incentive to handle nulls correctly all the way.

    And in Rust specifically, they made this cool little optimization where optional pointers are binary-compatible with regular nullable pointers - very nice when working with old C libraries.


  • I survived the hour long Uno hand

    @Gąska said in Waaah, I don't get paid to use new shiny languages:

    @izzion said in Waaah, I don't get paid to use new shiny languages:

    Also, I found this pretty funny:

    The first language on our list with a modern null alternative! Rust doesn’t have a null or nil value, and Rust developers use the Option pattern instead.

    // The value returned is either a Some of type T, or None
    enum Option<T> {
        Some(T),
        None,
    }
    

    :sideways_owl:

    In case you're not being ironic in your confusion, the important thing about option type is that it's part of type signature - the value can only be non-existent if it's explicitly marked as optional, and conversely, if it's not marked as optional, it's very definitely always existent. Very similar to non-nullable references that are all the rage in C# and Java nowadays, except with option type, it does that right thing by default - instead of opting out of every single input value being a ticking time bomb that can go missing when you least expect it, you have to opt-in - and when you opt-in, you have more incentive to handle nulls correctly all the way.

    And in Rust specifically, they made this cool little optimization where optional pointers are binary-compatible with regular nullable pointers - very nice when working with old C libraries.

    I'm neither ironic nor confused.

    I'm laughing at this Functional Programming elitist apostle thinking that the Option / None pattern isn't a null. It might be a type-aware null, but it's still null.


  • Banned

    @izzion it isn't a null in the classic sense of perfectly normal pointer just like any other except it's been given special semantic meaning and the power to make everything fall apart at any moment unless you make a null check literally every other line of code. The oft-quoted billion-dollar mistake line isn't about the concept of null itself, but about making it possible to appear literally everywhere.


  • I survived the hour long Uno hand

    @Gąska
    True, the compiler will now ding you before runtime that you're not adding your Nothing checks every other line of code. But otherwise, it doesn't do anything for reducing the amount of that boilerplate you have to write, as evidenced in the the example code right below that with fn try_division - you still have to slap in a pattern match to say "if I get Null Nothing back, here's my fallback handling, otherwise do what I really want you do to.


  • Banned

    @izzion said in Waaah, I don't get paid to use new shiny languages:

    @Gąska
    True, the compiler will now ding you before runtime that you're not adding your Nothing checks every other line of code.

    Wrong. It won't because you don't have to - moreover, you CANNOT - do the null checks anymore in like 99% of places because the type system forbids the null from even appearing there in the first place. And in the 1% of places where you actually expect the null value, it makes sure you won't forget it.


  • I survived the hour long Uno hand

    @Gąska said in Waaah, I don't get paid to use new shiny languages:

    @izzion said in Waaah, I don't get paid to use new shiny languages:

    @Gąska
    True, the compiler will now ding you before runtime that you're not adding your Nothing checks every other line of code.

    Wrong. It won't because you don't have to - moreover, you CANNOT - do the null checks anymore in like 99% of places because the type system forbids the null from even appearing there in the first place. And in the 1% of places where you actually expect the null value, it makes sure you won't forget it.

    Clearly you either didn't read my post or didn't read TFA 😝

    // This function handles a division that may not succeed
    fn try_division(dividend: i32, divisor: i32) {
        // `Option` values can be pattern matched, just like other enums
        match checked_division(dividend, divisor) {
            None => println!("{} / {} failed!", dividend, divisor),  <--NULL CHECK!
            Some(quotient) => {
                println!("{} / {} = {}", dividend, divisor, quotient)
            },
        }
    }
    


  • @izzion The point here isn't that the null checks don't exist, but that they're better.

    If it is not an Option type, then there is no null check. There can't be a null check, because there's no possibility of it being null. If there is an Option type, then the null check is not only there, it's required, which makes it so you can't forget to put it in and have the program blow up on you.

    Rust sucks for a number of unrelated reasons, but on this particular point they got it very right, and I wish .NET would implement something similar, turning nullability into something enforceable at the CLR type system level rather than the wishy-washy C#-language-only half-implementation we ended up getting, which is really a "the worst of both worlds" solution.


  • I survived the hour long Uno hand

    @Mason_Wheeler
    I'm not arguing it's not an improvement. Just that it's still (functionally, logically, and effectively) a null, and if you want to argue that a language "doesn't have nulls" because it uses the Option/None pattern instead, then I'm going to lampoon you.


  • Banned

    @izzion you've specifically chosen the exceptional example, something you encounter once every few thousand lines of code, where you ACTUALLY EXPECT a null to appear. This isn't what regular code looks like. Regular code looks like this (copied from a random file in NodeBB repo, because I couldn't think of a better example):

        async function (uid, roomId, newName) {
    		if (!newName) {
    			throw new Error('[[error:invalid-name]]');
    		}
    		newName = newName.trim();
    		if (newName.length > 75) {
    			throw new Error('[[error:chat-room-name-too-long]]');
    		}
    
    		const payload = await plugins.hooks.fire('filter:chat.renameRoom', {
    			uid: uid,
    			roomId: roomId,
    			newName: newName,
    		});
    		const isOwner = await Messaging.isRoomOwner(payload.uid, payload.roomId);
    		if (!isOwner) {
    			throw new Error('[[error:no-privileges]]');
    		}
    
    		await db.setObjectField('chat:room:' + payload.roomId, 'roomName', payload.newName);
    		await Messaging.addSystemMessage('room-rename, ' + payload.newName.replace(',', '&#44;'), payload.uid, payload.roomId);
    
    		plugins.hooks.fire('action:chat.renameRoom', {
    			roomId: payload.roomId,
    			newName: payload.newName,
    		});
    	};
    
    • This function never checks whether uid is null. Everything will violently blow up if it ever is.
    • This function never checks whether roomId is null. Everything will violently blow up if it ever is.
    • This function never checks whether the result of trim call is null. Everything will violently blow up if it ever is.
    • This function does check whether newName.length is null, but only by accident, and returns very misleading error message when it is.
    • This function never checks whether plugins, plugins.hooks or plugins.hooks.fire is null. Everything will violently blow up if it ever is.
    • This function never checks whether payload, payload.uid, payload.roomId or payload.newName is null. Everything will violently blow up if it ever is.
    • This function never checks whether Messaging, Messaging.isRoomOwner or Messaging.addSystemMessage is null. Everything will violently blow up if it ever is.
    • This function never checks whether db or db.setObjectField is null. Everything will violently blow up if it ever is.
    • This function never checks whether the result of replace call is null. Everything will violently blow up if it ever is.
    • Two potentially null values are passed to plugins.hooks.fire function in each call. If it ever actually happens to be null, it will take up to a few days to even tell where those nulls are coming from in the first place.
    • Two more potentially null values are passed to Messaging.isRoomOwner.
    • One more potentially null value is passed to db.setObjectField.

    You could argue none of this matter because you know these things will never be null, but do you really? The point of option types is to guarantee that yes, really, these things will never ever ever ever ever be null, it's just completely impossible. I can't imagine why you would ever NOT want that - for what's promised to be impossible to be actually impossible.



  • @Gąska That comparison is horrifically misleading on two different relevant points:

    • This function also doesn't check if any of those is undefined, that the awaited functions are async, that any of the functions exist or are of the right arity, that any of the objects have the correct shape, et cetera, et cetera. Javascript doesn't have type safety, so spotlighting that it doesn't have null-access prevention in the type safety that it already doesn't have is... :sideways_owl:
    • "Violent blowing up" is strictly contained to one spin of the message pump, not "everything". Whatever handles the Errors that are explicitly being thrown likely also handles the ReferenceErrors that the missing guards expose. Furthermore, even if nothing at all handles that error, only the current action is abandoned; the server keeps running, and (provided state is not inconsistent) all other requests both concurrently and in the future succeed independent of this one.

    If you want a more apt comparison, there are plenty of more appropriate languages to choose from -- ones where there's a type system that adding an Optional<> or Nullable<> makes sense and where code is written on the understanding that errors actually have consequences.


  • Banned

    @TwelveBaud said in Waaah, I don't get paid to use new shiny languages:

    @Gąska That comparison is horrifically misleading on two different relevant points:

    • This function also doesn't check if any of those is undefined, that the awaited functions are async, that any of the functions exist or are of the right arity, et cetera, et cetera. Javascript doesn't have type safety, so spotlighting that it doesn't have null-access prevention in the type safety that it already doesn't have is... :sideways_owl:

    Only half of those problems are due to JS retardery. The other half would exist in C# implementation too. But they wouldn't in e.g. Rust, because in Rust you just don't have potential nulls everywhere.

    • "Violent blowing up" is strictly contained to one spin of the message pump, not "everything".

    Nulls can get accidentally propagated into persistent data that will be retrieved all the time in other message handlers, screwing you forever and bringing the entire service down in ways that not even a reboot can fix. BTDT.

    If you want a more apt comparison, there are plenty of more appropriate languages to choose from

    Sure. But I don't feel like spending any more effort on a post that will most likely be either ignored or misunderstood yet again. If you have any particular better example in mind, feel free to post it and I'll dissect every invalid handling of nulls in it as well.

    The main point still stands - most of the time you don't care about nulls because you know they cannot be there anyway. Option type is just encoding this knowledge in type system.



  • @Gąska said in Waaah, I don't get paid to use new shiny languages:

    Nulls can get accidentally propagated into persistent data that will be retrieved all the time in other message handlers, screwing you forever and bringing the entire service down in ways that not even a reboot can fix. BTDT.

    :wtf_owl: Any even remotely competent message pump will have a system that keeps track of messages that have been processed, and if a given message fails to process more than X number of times, it shunts it off into an "errored messages" jail for developers to take a look at and then proceeds with the next message.


  • Banned

    @Mason_Wheeler I knew my post would be completely misunderstood but didn't expect it this way. I meant a situation where the message gets processed "successfully" because there were no null checks so nobody has noticed that there is any null to start with, and now you have bad data in DB.

    $5 that you won't understand this post either.


  • BINNED

    @Gąska said in Waaah, I don't get paid to use new shiny languages:

    First he introduces the most useless classification imaginable, and then he fucks it up!

    That is a common theme running through the entire article (which I've read first then skimmed more the further I got, because it's long :kneeling_warthog:). Just the paragraph directly above it he's got:

    Bear in mind, there’s no single perfect programming language. Some work best for back end / API development, others are great for system programming.

    Ah yes, back end vs. system programming, the dichotomy everyone keeps talking about. :sideways_owl:


    There are actually some interesting points throughout the whole thing, but he just keeps messing everything up with his inconsistency. Some random points I noticed reading:

    He starts with C++, "the worst of the worst", which might be a valid assessment if he didn't back it up with one of Linus's top 5 idiotic quotes, i.e. the guy who advocates for using C instead, which is strictly worse. Likewise, he ranks TypeScript lower than JavaScript. Did he even notice that?
    He complains about C++ being bloated with features, which is bad on his evaluation scale, except when further down we get to C# which he praises for "being improved with every release, with the addition of features like expression-bodied function members, pattern matching, tuples, and others."
    Next he gives it two thumbs down for bad "ecosystem/tooling", which is completely correct on the tooling part. That does suck. But for Python he gives a thumbs up on the "ecosystem" part because it "has a library almost for everything", which he completely he ignored here.

    The "speed" category is a joke: intentionally ill-defined to rate however he likes. C++ is thumbs down on speed because it's slow to compile, runtime performance be damned, Rust gets a thumbs up however (I'm told it compiles even slower than C++) because its runtime performance is a bit better than Go. For JavaScript and TypeScript the rating is mysteriously absent. Also no word about it for Haskell, F#, OCaml, etc. Just that for Scala apparently it's bad. The best language, Elixir, has a thumbs up for speed, but a new category "crunching numbers" with a thumbs down because it "doesn’t handle computationally-intensive tasks well".

    He also keeps pushing his dislike for OOP, lauding Go's lack of OOP features, with his rationale from the Clojure quote about "large object graph[s] of mutable objects", although mutability is an orthogonal concept.
    Along with immutability comes the praise for pure functions (and I completely agree with the advantages these have for reasoning about correctness, especially in concurrent code), but then Haskell and a few others get a thumbs down for being pure. It's like he threw dice to come up with the rating.

    The best parts are the completely ad-hoc categories: "React wasn’t made for JavaScript" or that Elm "doesn’t use React." Unfortunately I didn't understand a word in the corresponding JavaScript paragraph, so I don't know if he has a good point buried in this mess somewhere.

    I'm also curious what it means that "all of the functional languages below have built-in support for immutable data structures". Obviously most (all?) the other languages can support immutable data structures, with string being immutable for most of them. I'm sure he does have a point here, though, so what does the language support for immutability do?


  • Considered Harmful

    @izzion said in Waaah, I don't get paid to use new shiny languages:

    @Gąska
    True, the compiler will now ding you before runtime that you're not adding your Nothing checks every other line of code. But otherwise, it doesn't do anything for reducing the amount of that boilerplate you have to write, as evidenced in the the example code right below that with fn try_division - you still have to slap in a pattern match to say "if I get Null Nothing back, here's my fallback handling, otherwise do what I really want you do to.

    XQuery is a weird little ❄ of a language, but one of the interesting things about it is that you can use the same operations on zero, one, or many elements. A big reason jQuery (weird similarity in name but totally different beast) feels so easy-to-use is the same property: a jQuery instance might be referring to any number of (or no) elements, and the logic doesn't need to care. Also, fuck jQuery.


  • Considered Harmful

    @Mason_Wheeler said in Waaah, I don't get paid to use new shiny languages:

    If it is not an Option type, then there is no null check. There can't be a null check, because there's no possibility of it being null. If there is an Option type, then the null check is not only there, it's required, which makes it so you can't forget to put it in and have the program blow up on you.

    TypeScript has strict null checking mode, where it bitches at you any time you use an object without checking it for null. Of course, it doesn't work with most npm libraries, which either have incorrect annotations in their typing files or violate their contracts, so I never turn that thing on. Plus, it's annoying AF.

    What is nice are the nullish coalescing operator ?? and optional chaining operator ?..


    Filed under: What "are" nice? :fu: English language., Oh yeah, and don't forget JS has two distinct flavors of missing value: null and undefined


  • ♿ (Parody)

    @topspin said in Waaah, I don't get paid to use new shiny languages:

    @Gąska said in Waaah, I don't get paid to use new shiny languages:

    First he introduces the most useless classification imaginable, and then he fucks it up!

    That is a common theme running through the entire article (which I've read first then skimmed more the further I got, because it's long :kneeling_warthog:).

    You've got way more patience with it than I do. After the first few paragraphs of :wharrgarbl: I decided I'd sit back and rely on the rest of you to pick it apart for me.

    Was not disappointed. Enjoyed your rant.



  • @Gąska I do understand that, but that's not what you said. You said it will crash message handlers hard in a way that even rebooting won't fix. You said message handlers, you said nothing about databases, so I figured you were talking about a messaging system and not a database.



  • @topspin said in Waaah, I don't get paid to use new shiny languages:

    He starts with C++, "the worst of the worst", which might be a valid assessment if he didn't back it up with one of Linus's top 5 idiotic quotes, i.e. the guy who advocates for using C instead, which is strictly worse.

    Strictly worse how? C++ takes a bad imperative procedural language and makes it much, much worse by trying to bolt a bad object-oriented language onto it and bolting an abysmal metaprogramming language onto that. C is strictly better than C++ by virtue of not also having all the headaches that come from Templates and C++'s utterly broken object model.


  • Banned

    @Mason_Wheeler said in Waaah, I don't get paid to use new shiny languages:

    @Gąska I do understand that, but that's not what you said. You said it will crash message handlers hard in a way that even rebooting won't fix. You said message handlers, you said nothing about databases, so I figured you were talking about a messaging system and not a database.

    What do you think I meant by persistent data?


  • BINNED

    @Mason_Wheeler said in Waaah, I don't get paid to use new shiny languages:

    @topspin said in Waaah, I don't get paid to use new shiny languages:

    He starts with C++, "the worst of the worst", which might be a valid assessment if he didn't back it up with one of Linus's top 5 idiotic quotes, i.e. the guy who advocates for using C instead, which is strictly worse.

    Strictly worse how? C++ takes a bad imperative procedural language and makes it much, much worse by trying to bolt a bad object-oriented language onto it and bolting an abysmal metaprogramming language onto that.

    You can do all the low-level stuff in C++ that you can do in C, and you can also do all the archaic, error-prone, terrible things like C-strings, mallocmemory leaks, inventing your own object model (gobject, linux stuff) because you "hate OOP", goto, or shudder longjmp.

    You can also not do all that shit and instead use higher level abstractions that he mentioned, without incurring unreasonable runtime costs:

    • You can use std::strings instead of C strings. Containers and smart pointers remove the need for garbage collection, with RAII being miles ahead of malloc/free.
    • References are not nullable, unlike pointers and contrary to what he claims, while std::optional provides the mentioned Option pattern.
    • Likewise you can use something like Rust's Result<T,E> if you prefer that for error handling over exceptions, both of which are certainly better than C's errno.
    • The algebraic datatypes mentioned: std::variant is better than C's union.
    • You can create immutable data structures, as mentioned, more easily beyond a mere top-level const or opaque handle as you'd do in C.
    • Its type system is better (e.g. no unsound implicit conversions from void*)
    • You can at least do somewhat more functional-style programming he seems to like with things like algorithms, lambdas and std::function, which also helps with the threading functions (std::async, futures, etc.).
    • For concurrency you'll also get coroutines now.

    And lots more. Basically, you can and should use modern abstractions and practices, which compile down to the same code as if you wrote the same in C. If you managed to catch all the edge cases RAII catches, which you probably didn't.

    C is strictly better than C++ by virtue of not also having all the headaches that come from Templates

    No

    and C++'s utterly broken object model.

    It's no more broken than C's.


  • I survived the hour long Uno hand

    @topspin
    But since we're grading languages based on how young they are, it's unfair to the newer languages (which learned from the mistakes of all their predecessors) to give older languages credit for learning from their own mistakes. As such, we must only consider the older languages based on the language features that existed on their initial release. :tro-pop:


  • Banned

    @izzion fun fact: Rust wasn't even meant to compete in the system programming niche. Originally it was very GC-heavy and not performance-focused at all.


  • BINNED

    Unlike JavaScript, Python can’t be used for front end web development. However, it easily makes up for this with a huge number of data science libraries.

    :phb: … and our website is going to run entirely on Python.
    :dilbert: :wtf: That’s not even possible.
    :phb: But it has so many data science libraries! You’ll figure something out.

    inb4 “python interpreter running in webassembly”


    hey look, another example of the writer’s ignorance of basic features, wow!

    [Python] Has no built-in support for immutable data structures.

    >>> wtf = {'what','the','fuck'}
    >>> wtf.add('?!')
    >>> wtf
    {'fuck', '?!', 'the', 'what'}
    >>> wtf = frozenset(('what','the','fuck'))
    >>> wtf.add('?!')
    Traceback (most recent call last):
      File "<pyshell#12>", line 1, in <module>
        wtf.add('?!')
    AttributeError: 'frozenset' object has no attribute 'add'
    

    one more, I swear… TypeScript this time.

    How about the type system acting really weird at times?
    NaN === NaN; // -> false

    :rolleyes:


    In TypeScript, a circle’s area is πr². In ReasonML, the same code is 2πr.

    74bf4f7e-d53c-43d6-b229-84d35570e6bb-image.png


  • Banned

    @kazitor said in Waaah, I don't get paid to use new shiny languages:

    inb4 “python interpreter running in webassembly”

    HTH, HAND


  • Banned

    @kazitor said in Waaah, I don't get paid to use new shiny languages:

    [Python] Has no built-in support for immutable data structures.

    >>> wtf = {'what','the','fuck'}
    >>> wtf.add('?!')
    >>> wtf
    {'fuck', '?!', 'the', 'what'}
    >>> wtf = frozenset(('what','the','fuck'))
    >>> wtf.add('?!')
    Traceback (most recent call last):
      File "<pyshell#12>", line 1, in <module>
        wtf.add('?!')
    AttributeError: 'frozenset' object has no attribute 'add'
    

    I hate to be on that dimwit's side here, but this isn't what's usually understood as immutable data types. It's not just about being immutable - it's also (I'd even say mostly) about memory-efficient partial copies so that the data can still be worked on (in particular, adding/removing elements from a list or other container) with reasonable enough performance (ie. not requiring full copy of everything whenever you want to modify the container). Freezing collections doesn't give you that.

    Granted, I'm sure there's some popular library that handles it well. It's not that hard to implement, after all. But AFAIK it's not part of the standard library.


  • BINNED

    @topspin said in Waaah, I don't get paid to use new shiny languages:

    @Mason_Wheeler said ...

    I knew instead of trying to give a reasonable reply I should have just downvoted, as that's the modus operandi. 🏆


  • BINNED

    @Gąska said in Waaah, I don't get paid to use new shiny languages:

    I hate to be on that dimwit's side here, but this isn't what's usually understood as immutable data types. It's not just about being immutable - it's also (I'd even say mostly) about memory-efficient partial copies so that the data can still be worked on

    I think that is called immutable data types, with the efficient copy ones being called persistent data types. At least I've seen it called that and he does too, but it's just a matter of definition.

    My question remains: does "language support" for it (whether you call it immutable or persistent data types) mean just that the standard library ships with some of these data types, or is there actually anything in the language instead of the library that makes them easier to write?


  • Banned

    @topspin my perspective is that C++ showed beyond any doubt that you don't need any language support for container types whatsoever. It's quite nice if done right, but it doesn't change all that much (and creates a risk of non-standard types being very awkward to use compared to builtins, discouraging programmers from using anything but built-ins).

    As for specific examples of what they might've meant, maybe something like list patterns in ML-like languages, which allows destructuring a list into individual variables like a tuple. Scala allows user-defined destructuring in nearly arbitrary form, but e.g. OCaml is hardcoded to recognize list patterns as standard lists, and thus using any data type that's not a list - including those from standard libraries - is significantly more awkward.


  • Discourse touched me in a no-no place

    @boomzilla said in Waaah, I don't get paid to use new shiny languages:

    Also they can only rely on the data passed as parameters.

    No; the data could also be bound in by context/closure capture. The data was a parameter somewhere but isn't necessarily a parameter you directly gave in this call.


  • Discourse touched me in a no-no place

    @izzion said in Waaah, I don't get paid to use new shiny languages:

    Just that it's still (functionally, logically, and effectively) a null

    And probably implemented with null too, at least when the wrapped type is a reference type. That's such an obvious implementation approach.


  • ♿ (Parody)

    @dkf said in Waaah, I don't get paid to use new shiny languages:

    @boomzilla said in Waaah, I don't get paid to use new shiny languages:

    Also they can only rely on the data passed as parameters.

    No; the data could also be bound in by context/closure capture. The data was a parameter somewhere but isn't necessarily a parameter you directly gave in this call.

    I guess I asked for that, but it fits the spirit of my comment where I almost wrote about not relying on global variables.


  • Discourse touched me in a no-no place

    @Mason_Wheeler said in Waaah, I don't get paid to use new shiny languages:

    C is strictly better than C++ by virtue of not also having all the headaches that come from Templates and C++'s utterly broken object model.

    There are four primary features of C++ over C (plus a whole load of standard library stuff): OO, templates, exceptions, and operators.

    1. OO is weird in C++ because they decided to make structs be objects, and as a consequence had to not have a root class; lots of bad things in C++ stem from that decision. (If they'd split that, they'd have been able to say that fields of classes can be reordered by the compiler and so on while still allowing the exact layouts needed for direct memory access through structures.)
    2. Templates are really very complicated, mostly because figuring out exactly what is going on is really hard. It's a damn shame that you can't specify type constraints directly in the template; this is an area where Java and C# are much nicer precisely because they use the type system better. (They also don't allow for non-type template parameters. That's both limiting and wonderful as that's a very special deep rabbit hole.)
    3. Exceptions are actually a good thing… except for allowing arbitrary types as exception values and not having especially clear semantics for ownership semantics. (GC really simplifies exception handling a lot; that's why both Java and C# do really well with exceptions.)
    4. Operators are one of those things that is great except they're really badly abused by people who don't know what a group, ring or field is. And you can't add your own symbols. And there's the type casting operators. And some things are overridable operators that really shouldn't ever be. And shit this list is starting to get long…


  • To summarize, C++ overall is

    @dkf said in Waaah, I don't get paid to use new shiny languages:

    one of those things that is great except they're really bad


  • Considered Harmful

    @topspin said in Waaah, I don't get paid to use new shiny languages:

    @topspin said in Waaah, I don't get paid to use new shiny languages:

    @Mason_Wheeler said ...

    I knew instead of trying to give a reasonable reply I should have just downvoted, as that's the modus operandi. 🏆

    I just somehow misread this as modulus operandi and stared for like a minute trying to figure out the joke.

    Status: God, I need coffee.


  • Trolleybus Mechanic

    @Gąska said in Waaah, I don't get paid to use new shiny languages:

    @kazitor said in Waaah, I don't get paid to use new shiny languages:

    [Python] Has no built-in support for immutable data structures.

    >>> wtf = {'what','the','fuck'}
    >>> wtf.add('?!')
    >>> wtf
    {'fuck', '?!', 'the', 'what'}
    >>> wtf = frozenset(('what','the','fuck'))
    >>> wtf.add('?!')
    Traceback (most recent call last):
      File "<pyshell#12>", line 1, in <module>
        wtf.add('?!')
    AttributeError: 'frozenset' object has no attribute 'add'
    

    I hate to be on that dimwit's side here, but this isn't what's usually understood as immutable data types. It's not just about being immutable - it's also (I'd even say mostly) about memory-efficient partial copies so that the data can still be worked on (in particular, adding/removing elements from a list or other container) with reasonable enough performance (ie. not requiring full copy of everything whenever you want to modify the container). Freezing collections doesn't give you that.

    Granted, I'm sure there's some popular library that handles it well. It's not that hard to implement, after all. But AFAIK it's not part of the standard library.

    I've always taken immutable to mean nothing more than being immutable. Being able to build up efficiently or do partial copies are a thing that allows you to do, but I would never consider it a requirement of an immutable data type.


  • area_pol

    WTF is this garbage article? This guy mixes concepts all around and spreads misinformation time and time again. I like how literally every thumbs down of Rust is false:

    Rust is the only modern language on our list with no garbage collection. This forces the developers to think about low-level memory management and makes developer productivity suffer.

    I have yet to see any manual memory management in Rust, despite no GC. Granted, some extremely low-level crates might use it, but for the most time, nobody will ever touch an allocator. The language forces to NOT think about this stuff.

    Due to the lack of garbage collection, concurrency is rather hard in Rust.

    FFS, show me another language which gives me the guarantee of no synchronization bugs for formally correct programs. If it builds, you have proper concurrency - can't get any easier than that. If one wants to write in the unsafe dialect and shoot himself in the foot - it's possible, but it needs to be explicit.

    Rust has no built-in support for immutable data structures.

    Everything in Rust is immutable by default.

    Being a low-level language, developer productivity in Rust can’t be as high as in other higher-level languages.

    That depends on the definition of high-level. Rust does have ORMs, web frameworks, DI containers - all the fancy stuff to write high-level code. Where productivity might suffer is not related to being high- or low-level - it's rather the safety mechanisms built into the language, which can be a hinderance.



  • @dkf said in Waaah, I don't get paid to use new shiny languages:

    t's a damn shame that you can't specify type constraints directly in the template; this is an area where Java and C# are much nicer precisely because they use the type system better.

    They finally got their shit together in C++20:

    (Sure, it's been on the table for a while now, and it isn't a trivial feature, especially considering all the things you can do with templates.)



  • @error said in Waaah, I don't get paid to use new shiny languages:

    @Mason_Wheeler said in Waaah, I don't get paid to use new shiny languages:

    If it is not an Option type, then there is no null check. There can't be a null check, because there's no possibility of it being null. If there is an Option type, then the null check is not only there, it's required, which makes it so you can't forget to put it in and have the program blow up on you.

    TypeScript has strict null checking mode, where it bitches at you any time you use an object without checking it for null. Of course, it doesn't work with most npm libraries, which either have incorrect annotations in their typing files or violate their contracts, so I never turn that thing on. Plus, it's annoying AF.

    What is nice are the nullish coalescing operator ?? and optional chaining operator ?..

    My favorite thing about TypeScript's "strict mode" is the way it's incapable of remembering things. Let's say you have a type like this, an object full of nested optional objects:

    var thing: { a?: { b?: { c?: string } } } = { a: { b: { c: "pie!" } } };
    

    And then you start using Lodash everywhere, so there are lots of calls to _.isEmpty and _.isNil scattered around, because Lodash handles the null-checking for you and ends up usefully terse. Then you get "errors" like this:

    if (!_.isEmpty(thing.a.b.c)) {
       console.log("what's b? " + JSON.stringify(thing.a.b));
    }
    

    And the strict-mode compiler will say: thing.a is nullable, so thing.a.b doesn't necessarily exist, go null-check it!

    If you'd used thing.a.b.c == null instead of _.isEmpty, then the above code works as you'd like – the compiler is bright enough to see that we're inside of an if block where thing, a, b, and c were all verified to be non-nil. But TypeScript can't figure out what's going on inside functions, so it throws errors at you: Lodash, which you've scattered everywhere because of how useful it is, has suddenly become an impediment. But fortunately, TypeScript gives you an out! Much like ?. is short for "access that property, or give me undefined if the object I was using was nil", TypeScript has !., the "shut up you damn compiler, I know it's not null, stop bothering me!" operator.

    This is causing a bit of a rift in my current team. Some of the team is working mostly on new code (and/or they refactored all of their old code to cater to strict mode in a much nicer way than my example – their code is almost C#-like in its "three extra layers of abstraction, but now it's more provably correct"), and some of the team is working mostly on old code. Strict mode hates the old code, because the old code gets its types from a generator that makes everything optional.

    I should really write up a proper rant on this; strict mode is nice in theory, but it has a lot of hoops to jump through, so it's only really good if you're prepared to jump through those hoops.


  • Considered Harmful

    @PotatoEngineer said in Waaah, I don't get paid to use new shiny languages:

    If you'd used thing.a.b.c == null instead of _.isEmpty, then the above code works as you'd like – the compiler is bright enough to see that we're inside of an if block where thing, a, b, and c were all verified to be non-nil. But TypeScript can't figure out what's going on inside functions, so it throws errors at you: Lodash, which you've scattered everywhere because of how useful it is, has suddenly become an impediment. But fortunately, TypeScript gives you an out! Much like ?. is short for "access that property, or give me undefined if the object I was using was nil", TypeScript has !., the "shut up you damn compiler, I know it's not null, stop bothering me!" operator.

    The problem is that the lodash type files (.d.ts files) don't indicate that they're performing a type assertion. This is more a problem with the library than the language, but the end result is it's too unwieldy to actually use either way.



  • @error That's what I "love" about Typescript - not only do you have to deal with the quirks, no you have to learn a separate definition language as well. The stuff in those .d.ts files sometimes is downright funky.



  • @error Having worked with a handful of js libraries with incomplete or out of date .d.ts files, I'll confirm that it's a pain in the ass.


Log in to reply