C stringsþÝ«ÌΉŠ‹ÿ


  • Discourse touched me in a no-no place

    @Maciejasjmj said:

    And it's also a horrible idea.

    It depends on what you're using it for; some use-cases are made enormously simpler if there's a default (e.g., counting the different types of characters in a string, which becomes utterly trivial code when you've got a default zero). But to be honest, I'd rather have the ability to explicitly set the default value for a map/dictionary when I want it, instead of having it thrust upon me.


  • Banned

    @ben_lubar said:

    A nil slice or map acts like a read-only empty slice or map. A nil channel acts like a blocking channel with nothing on the other side.

    And nil struct/object/whatever complex variable that isn't container?



  • @Gaska said:

    >ben_lubar:

    C++ solves the problem by avoiding pointers where possible

    Avoiding pointers my ass.

    If we're talking about "null objects", meaning incomplete or missing objects, I'd say C++ avoids the problem by not allowing their existence. When a constructor finishes, the object that is produced is a valid object of that type.

    Constructor failure is meant to be handled by throwing an exception, so that invalid objects are never constructed. Since people have a pathological fear of exceptions, what is often done instead is find ways to return an error from the constructor (factory pattern, output parameters, init method, etc) and an "is ok" check. As far as the language is concerned, however, those are valid objects. You've simply cleverly managed to avoid the language's safety features so you can introduce more bugs.

    In situations where you'd want to defer the construction of an object, or you want to wait for an object to be given to you, you can use a null pointer as a placeholder. Dereferencing a null pointer is wrong and if you're lucky you'll get a quick crash. In well formed programs, a pointer can only ever be a null pointer or a pointer to a valid object. Invalid objects can't exist.


  • Banned

    @Kian said:

    Constructor failure is meant to be handled by throwing an exception, so that invalid objects are never constructed.

    Except the object is constructed - a so-called zombie object which was partially constructed, ie. doesn't represent a valid object, but you have no way of knowing it if you don't manually create mechanism for detecting if the construction succeeded (e.g. bool isProperlyConstructed = false that is set to true at the end of constructor). If your constructor can throw, you absolutely MUST handle zombie object case, because this zombie object will be destructed using the very same code that's used to destroy fully constructed objects.


  • Discourse touched me in a no-no place

    @Gaska said:

    If your constructor can throw, you absolutely MUST handle zombie object case, because this zombie object will be destructed using the very same code that's used to destroy fully constructed objects.

    Surely you can just use RAII to handle that for all the members? Or is that something we're supposed to pretend isn't a thing in this case?

    I suspect that the pathological fear of exceptions in C++ is a consequence of their semantics being a little bit wrong at some point in the past. This is an area where Java and C# win massively; their exception semantics are correct, and have been from the beginning. (I suspect that it is in part related to the difference in reference semantics between the languages.)



  • No, that's factually wrong. An object that throws in the constructor will not be destructed. If the object contains other objects itself, the objects that managed to be constructed before the exception is throws will be destructed in the reverse order of construction, but that's not the same as calling the destructor of the whole object.

    That is to say, if you have an object like so:

    class ClassC
    {
        ClassA one;
        ClassB two;
        ClassC();
    }
    

    The constructor for ClassC will call, in order, the constructors for ClassA and ClassB before doing it's own work.

    • If the constructor for ClassA throws, no destructor is called.
    • If the constructor for ClassB throws, the destructor for ClassA will be called. No other destructors called.
    • If the constructor for ClassC throws, the destructors for ClassB and ClassA will be called in that order.

    This, of course, applies recursively. If ClassA or ClassB are composed of objects themselves, the destructors for their member objects will be called if the objects managed to be created before the exception was thrown.



  • I think the fear of exceptions comes from them being relatively new when C++ introduced them to the mainstream, so people didn't know how to handle them effectively. Which led to lots of unnecessary try-catches and general misuse. It took a while before exception safety was properly understood and easy to make guarantees about.

    Nowadays, you can learn all you need to know in a couple of hours in any of the C++ conferences. Here's a link to one guy that explains how to take advantage of C++ exceptions: http://exceptionsafecode.com/ Found his talk on YouTube very clarifying.


  • Discourse touched me in a no-no place

    @Kian said:

    I think the fear of exceptions comes from them being relatively new when C++ introduced them to the mainstream, so people didn't know how to handle them effectively. Which led to lots of unnecessary try-catches and general misuse. It took a while before exception safety was properly understood and easy to make guarantees about.

    C# and Java have two advantages here:

    1. Mandatory garbage collection. That hugely simplifies cleaning up after an exception has been thrown, as most objects can be just reclaimed in the runtime's own time rather than everything having to figure out how to do it immediately.
    2. Single class that is the root of all exceptions. This reduces the crazy. (C++ is getting there with std::exception, but there's a lot of legacy code.)


    1. GC is not an advantage, and it certainly isn't better than the C++ approach. Following the RAII idiom, all classes would offer the basic exception safety guarantee (no leaks) by default. In fact, exceptions and RAII are meant to complement each other. If an exception is thrown, resources clean up after themselves. It also becomes easy to provide the strong safety guarantee, allowing you to provide transactional semantics (either you succeed or you throw and stay in your previous state).
    2. std::exception was always there, as far as I know. If people ever made exception classes that don't inherit from it, they're TRWTF.


  • @Gaska said:

    Avoiding pointers my ass

    I will agree not to point to your ass.



  • @Kian said:

    If we're talking about "null objects", meaning incomplete or missing objects, I'd say C++ avoids the problem by not allowing their existence. When a constructor finishes, the object that is produced is a valid object of that type.

    Slight problem: In order to use polymorphism, you need to use pointers as C++'s implementation of RIAA would try to initialize the (likely abstract) base class when you declare it.


  • Banned

    @Kian said:

    No, that's factually wrong. An object that throws in the constructor will not be destructed. If the object contains other objects itself, the objects that managed to be constructed before the exception is throws will be destructed in the reverse order of construction, but that's not the same as calling the destructor of the whole object.

    Wow, that's neat. Now I know where this whole performance overhead with exceptions comes from...

    @flabdablet said:

    I will agree not to point to your ass.

    Assuming that sentence has flawed grammar because I CBA to learn how to properly use language I'm using so you should read the sentence differently from what it's written like since obviously that's not what I meant? What a dick move.



  • @Gaska said:

    What a dick move.

    I will certainly agree not to point to your ass with my dick.


  • Banned

    @flabdablet said:

    I will certainly agree not to point to your ass with my dick.

    Make me look like a homophobe? That's even worse dick move.

    INB4 literal interpretation of "dick move".



  • @FrostCat said:

    I would suspect that's a filesystem limitation, not an OS one, but I'm not going to bother to create an ext2fs partition on a USB drive to test it.
    It's an OS limitation. FAT supports names of up to 11 bytes, explicitly using 1 byte per character. Both EXT2 and NTFS support names of up to 255 bytes, with no limitation on contents whatsoever. (On NTFS, that's 127 characters, since it's UCS-2/UTF-16; in EXT2, no assertion is made regarding character set.) In Linux, the forbidden characters are \0 and /. In Windows at the kernel level, the forbidden characters are \0 and '\\'. The Windows "personality" adds all those other regulations, plus the one that file names must have at least one non-space, non-. character, with Windows Explorer tacking on that filenames must not start with ..

    Long story short, there's a folder in my home folder called .".". and SFU Bash on Vista handles it just fine, and there's another folder there called \\/\\/ that I can ntfsprogs from Linux on all day.



  • @Gaska said:

    That's even worse dick move.

    You're upset because I won't flirt with you. That's OK, I understand; I'm not offended.



  • @Gaska said:

    Mind you, I also hate [...] Clausewitz Engine scripts
    And it doesn't help that Paradox's execution engine is buggy, requiring hacky workarounds that bump into (understandable) language limitations that require yet worse workarounds.
    Otherwise you get a king that's his own mother!



  • @dkf said:

    This is because, with the exception of char and short (and the types related to/derived from them) everything has to be aligned to at least a 4 byte boundary. [...] Try to access a 32-bit value that isn't aligned and you'll get a bus errorget slow but otherwise perfectly functional A-OK code.
    FTFY


    Filed under: Unless you're coding for a Wii-U, we need a new tag cloud to attack


  • Banned

    @TwelveBaud said:

    And it doesn't help that Paradox's execution engine is buggy, requiring hacky workarounds that bump into (understandable) language limitations that require yet worse workarounds.

    I think the worst part is syntax. "manpower = 10" increases manpower by 10,000, whereas "manpower = 0.1" increases it by 10% of manpower limit, and "energy = 10" increases energy production by 10%. Also, it's very, very context sensitive and the language itself is not documented at all, so scripting things is a giant guessing game. That's what you get if you want same language for map creation, units definitions and game events.



  • temperatures := make(map[string]int)
    if v, ok := temperatures["Alaska"]; ok {
        fmt.Println("Alaska's temperature is", v)
    }
    


  • @ben_lubar said:

    ```
    temperatures := make(map[string]int)
    if v, ok := temperatures["Alaska"]; ok {
    fmt.Println("Alaska's temperature is", v)
    }

    
    
    You... do know that Java Maps have [getOrDefault](http://docs.oracle.com/javase/8/docs/api/java/util/Map.html#getOrDefault-java.lang.Object-V-) for this exact purpose?
    
    Also, discourse won't quite code blocks properly.
    
    *EDIT: quoted code blocks need extra line breaks -b*

  • Java Dev

    I think that's not 'or default' but success as a 2nd return value.


  • FoxDev

    @PleegWat said:

    I think that's not 'or default' but success as a 2nd return value.

    this.

    it also makes me feel icky to the point that i would rather use brainfuck as a programming language than Go.....

    and you know,what? i'm not sorry.


  • kills Dumbledore

    I can see that multiple return values could be useful, but that code is hard to parse between the lack of brackets around the if condition, line continuing after the semi colon and general Go-ness



  • I assume you don't like for loops, then?


  • FoxDev

    @Jaloopa said:

    I can see that multiple return values could be useful

    i remember my C days where if you forgot to check the error codes you were in a world of hurt, and.... well i still occasionally have flashbacks about that....



  • @powerlord said:

    Slight problem: In order to use polymorphism, you need to use pointers as C++'s implementation of RIAA would try to initialize the (likely abstract) base class when you declare it.

    Well, you need pointers because you are accessing an object whose type you don't know any more. When the object is created in the first place, you know the concrete type. You forget it later because you want to use the same interface to several different concrete types. I guess I'm not sure what the slight problem you're talking about is?

    Also, it's RAII, not RIAA. Resource Aquisition Is Initialization. Yes, it's a dumb acronym and not even Stroustrup, the one that came up with it, likes it.

    @Gaska said:

    Wow, that's neat. Now I know where this whole performance overhead with exceptions comes from...
    Well, the performance hit is only for when exceptions are thrown. If you don't throw, it's free. It's a trade-off, exceptions speed up the "happy path" at the expense of slower error handling. It's a trade-off I think is worthwhile. Hopefully your program isn't chugging along throwing exceptions all the time.


  • kills Dumbledore

    Are you saying it's actually if (v, ok := temperatures["Alaska"]; ok) {...?

    Because that makes marginally less sense



  • @PleegWat said:

    I think that's not 'or default' but success as a 2nd return value.

    In Java, Maps only store reference types. Not surprisingly, the default for reference types is null, which is what gets returned if you use get with a key that doesn't exist.

    This allows you to specify a more sane return value for the default, such as Integer.valueOf(0).



  • I want C++ to die just so I never have to hear about RAII again.



  • It's more like

    {
        v, ok := temperatures["Alaska"]
        if (ok) {
            // ...
        }
    }
    


  • Considering Go is being proposed as an alternative, I hope C++ has a long and healthy future. Rust looks interesting, though I'm not inclined to bet on it until they settle on an interface.


  • kills Dumbledore

    So it's a vaguely sensibly written piece of code, then someone selected a line and dragged it down into the middle of the next line by accident, whereupon the Go language design team assumed it was intentional and wrote the spec around it



  • It's basically a way to have a variable scoped to the if statement without indenting and using an extra set of braces. It happens a lot more than you'd think.



  • @Kian said:

    Rust looks interesting

    Rust looks more interesting than Go, for sure... 🚎



  • I tried picking up Rust. But after staring at the ridiculous syntax and well, I literally need a 3rd monitor to keep looking up every stupid character because it keeps changing shit.

    All Rust is promoting is security by obfuscation but maybe it's just me.



  • @delfinom said:

    ridiculous syntax

    If 20 years of C++ programming left me with anything (aside from feeling slightly dead inside), it would be a stupidly high tolerance to ridiculous syntax.

    @delfinom said:

    changing shit

    Yeah, it's currently at version α 0.0.0.0.3 or something, and probably won't be stable for a good while yet. That does mean they have a chance to standarize on some non-ridiculous syntax at some point.

    (Personally I would've used fun rather than fn to introduce a function definition. Because programming should be fun! Oh well.)



  • Nah, they should have stuck with let for both functions and variables. After all, constants are just functions that always return the same value, and variables can be thought of as function pointers to functions that take no parameters.


  • Banned

    @Kian said:

    Well, the performance hit is only for when exceptions are thrown. If you don't throw, it's free.

    What about preparing stack for handling "some of these objects might or might not need destruction at the end of scope" situation? I think it's non-trivial thing, and must be done for every non-nothrow-constructible object?

    @blakeyrat said:

    I want C++ to die just so I never have to hear about RAII again.

    Your beloved C# also has RAII. Do you want it to die too?

    @Kian said:

    Rust looks interesting, though I'm not inclined to bet on it until they settle on an interface.

    They did. Almost. 1.0-alpha was released last week, and beta is planned at February; they promise no more breaking changes from then on (unless critical bug is found).

    @ben_lubar said:

    ```
    temperatures := make(map[string]int)
    if v, ok := temperatures["Alaska"]; ok {
    fmt.Println("Alaska's temperature is", v)
    }

    let map: HashMap<&str, i32> = HashMap::new();
    if let Some(x) = map.get("Alaska") {
    println!("Alaska's temperature is {}", x);
    }

    
    @delfinom <a href="/t/via-quote/6871/286">said</a>:<blockquote>I tried picking up Rust. But after staring at the ridiculous syntax and well, I literally need a 3rd monitor to keep looking up every stupid character because it keeps changing shit.</blockquote>
    As I mentioned, they've already stabilized on syntax. And it's much better looking than year ago. I'd recommend you giving it a second try. It requires getting used to, but you can say that about every language - and while the last-statement-that-doesn't-end-with-semicolon-is-the-return-value thing is counterintuitive at first, I started to really love it after some time (since `if` and `match` are expressions, I only ever need to write `return` for early exits, which is surprisingly rare). Also, for-each operates on iterators, not containers - at first it feels like just more characters to write each time, but the added flexibility is really amazing for non-container iterators (e.g. generators).
    
    @tar <a href="/t/via-quote/6871/287">said</a>:<blockquote>Yeah, it's currently at version α 0.0.0.0.3 or something, and probably won't be stable for a good while yet.</blockquote>
    The language is stable as it is now; only some very obscure features and the less important half of standard library are subjects to change (and most probably they won't change either). And in just six weeks, you'll get fully stabilized interface in beta version.
    
    @Kian <a href="/t/via-quote/6871/288">said</a>:<blockquote>Nah, they should have stuck with let for both functions and variables. After all, constants are just functions that always return the same value, and variables can be thought of as function pointers to functions that take no parameters.</blockquote>
    Except Rust is pretty low-level language, and on low level, code and data is very different.


  • @Gaska said:

    Your beloved C# also has RAII. Do you want it to die too?

    C# developers don't constantly mouth-on about it as if they were reading holy scripture.


  • Banned

    @blakeyrat said:

    C# developers don't constantly mouth-on about it as if they were reading holy scripture.

    I didn't start this GC vs RAII war here. It was that JavaScript guy who did.


  • Winner of the 2016 Presidential Election

    @blakeyrat said:

    C# developers don't constantly mouth-on about it as if they were reading holy scripture.

    TRWTF is that they have to do that because of all the morons who are Doing It Wrong™. People should have to get a license before they're allowed anywhere near a C++ compiler.



  • (On mobile, so I guess I broke this quote.)

    @Gaska said:


    let map: HashMap<&str, i32> = HashMap::new();
    if let Some(x) = map.get("Alaska") {
    println!("Alaska's temperature is {}", x);
    }

    Other than the use of {} where I'd prefer %d, that looks entirely reasonable. Will take another look (once I've finished reading Learn you a Haskell...


  • ♿ (Parody)

    @blakeyrat said:

    C# developers don't constantly mouth-on about it as if they were reading holy scripture.

    They're too busy proselytizing the rest of their crap. (And they probably don't understand the C++ guys anyways.)


  • Banned

    @tar said:

    Other than the use of {} where I'd prefer %d, that looks entirely reasonable.

    %d would be unnecessary duplication of type information, because the function already knows the parameter needs to be integer (it's all statically typed). Also, {} is uniform with {x} "put x'th argument here" syntax, and with {:?} "print debug string" syntax (the latter was recently introduced to differentiate between classes that can be converted into readable string and classes for which string representation is useful for debugging).



  • @Gaska said:

    What about preparing stack for handling "some of these objects might or might not need destruction at the end of scope" situation? I think it's non-trivial thing, and must be done for every non-nothrow-constructible object?

    I'm not a compiler writer, so I don't know the gritty details. I "know" (I've read and been told, haven't bothered to test it myself) that there's "no cost" unless you actually throw. When you throw, it's expensive. Here's a write up, if you are interested, of the trade-offs involved: http://mortoray.com/2013/09/12/the-true-cost-of-zero-cost-exceptions/



  • @Gaska said:

    the function already knows the parameter needs to be integer

    %d means "print in decimal, as opposed to %x, or "print in hex". printf() has always been more flexible and easier to use than iostreams in that regard...


  • Banned

    @tar said:

    %d means "print in decimal, as opposed to %x, or "print in hex".

    {:x} for lowercase or {:X} for uppercase hex. Can be used with any type implementing LowerHex or UpperHex trait, respectively. And for pointers, there's {:p} and Pointer trait.



  • OK, I could probably get used to that syntax eventually (but that's not as much fun as me shouting "NO! UNACCEPTABLE!! PRINTF IS THE ONE TRUE WAY!!!").

    Can I do stuff like this with these format strings?

    println!("a={1:x} b={0:x}", b, a);


  • Java Dev

    I'd hope it can do everything printf can? Placeholder width, precision, truncation. Does it include time formatting?

    Is there a documentation page?


Log in to reply