How can we increase adoption of c/c++ alternatives?



  • @Groaner said:

    stack semantics and deterministic destruction start to become a lot more appealing than every object being a heap allocation to be disposed of by some garbage collector that's "smarter than you."

    http://www.pipeline.com/~hbaker1/LazyAlloc.html

    … and so on …

    Oh, and if you're allocating every object on the heap, the garbage collector is smarter than you.


  • Discourse touched me in a no-no place

    @tufty said:

    the garbage collector is smarter than you

    I know, I know. But you don't have to rub it in.



  • @tufty said:

    Oh, and if you're allocating every object on the heap, the garbage collector is smarter than you.

    Except that it doesn't know when it's appropriate to run. Generally, for interactive applications like games, you'd rather spend a fixed 0.5 ms per frame than 5 ms randomly once per 100 frames. The former you can count into your per-frame budget, the latter will cause noticeable lag spikes that you can do little about.

    Another feature of C++-style destructors is that they can help you with managing resources when you use stuff like memory/object pools etc etc.

    Finally, Java-style everything-goes-to-the-heap really sucks if you want to use a lot of small utility classes, like your 3D and 4D vectors. In C/C++, you stick those onto the stack and everything is fine. In Java, you'll have to allocate them on the heap (and risk triggering the GC), use pools (and risk memory leaks), or write really wonky code.




  • Discourse touched me in a no-no place

    @cvi said:

    Finally, Java-style everything-goes-to-the-heap really sucks if you want to use a lot of small utility classes, like your 3D and 4D vectors. In C/C++, you stick those onto the stack and everything is fine. In Java, you'll have to allocate them on the heap (and risk triggering the GC), use pools (and risk memory leaks), or write really wonky code.

    You should read up on how modern GC and JIT compilation actually works. The young generation objects are deleted on a prioritised schedule, because most of them have such a short lifespan, and that's where the JITter doesn't decide to just put the structure on the stack for you (because it has enough information to decide when that's actually safe to do).

    The downside of the C++ approach is that when things get complicated, debugging it is foully hard. (It's a little easier when you're working with a language like Java, as then you're at least looking for an existing connection in the graph of objects which shouldn't be there, instead of looking for code which is missing; looking for the place where something should be but isn't is rather difficult.) Also, C++ is the only language where shutting down the program can make it hang for ages and then shit itself (while it pages things back in trying to deallocate everything, and then hits a bug in some destructor somewhere); everyone else uses a different approach which is much faster (deallocating memory on exit is a waste, so exit handlers are just used to do important stuff like shutting down database connections cleanly and flushing writer channels).

    But I'll freely admit that C++ is easier to use than it used to be, provided you don't dive too deep. It used to be horrendous, and now it is only that bad if you decide to start playing Very Clever Template Games…



  • @Buddy said:

    http://www.mono-project.com/Working_With_SGen#Controlling_Collections

    Unfortunately, "very fast" doesn't provide any information on the upper bound of the run time. To be fair, the following holds true both with and without GC:

    The best mechanism to avoid these pauses is to not allocate memory during time sensitive operations and instead move the majority of the object allocations out of the sensitive code paths or your main game loop for example.


  • @dkf said:

    You should read up on how modern GC and JIT compilation actually works.

    Yeah, I probably should. What I described was an actual problem that I had encountered some time ago (~2 years). A lot of the allocated objects were passed across function boundaries, and sometimes in structures containing several such objects, so that perhaps made the situation worse.

    Also, C++ is the only language where shutting down the program can make it hang for ages and then shit itself (while it pages things back in trying to deallocate everything, and then hits a bug in some destructor somewhere); everyone else uses a different approach which is much faster (deallocating memory on exit is a waste, so exit handlers are just used to do important stuff like shutting down database connections cleanly and flushing writer channels).

    Yeah, bugs in destructors that execute at exit are messy. For extra fun, have a global context that you have little control over (e.g., a CUDA runtime context) involved.

    [...] now it is only that bad if you decide to start playing Very Clever Template Games…

    :-( One of the things I miss in many potential alternative languages is C++'s meta-programming capabilities... Not that C++ templates are the best solution to this. At least people are starting to look at this a bit more (see e.g., Terra).



  • You rang?

    C# is my vote.


  • Discourse touched me in a no-no place

    @cvi said:

    One of the things I miss in many potential alternative languages is C++'s meta-programming capabilities... Not that C++ templates are the best solution to this. At least people are starting to look at this a bit more (see e.g., Terra).

    Both Java and C# do substantial amounts of metaprogramming, but they tend to do it in a very different way. Essentially, when you can use use runtime code generation and runtime optimisation, you don't need quite as complex a system of metaprogramming in the compiler. (Higher level languages like Python do even more, but worry far less about how to spit machine code out the end.)


  • :belt_onion:

    @Onyx said:

    To the poor soul that inherits some of my code: I'm sorry. I'm so, so sorry. But I had a week and Stack Overflow...

    I've put similar comments in things I've written.
    Usually similar circumstances. The other big one is - I get zero design specs, so I whip something together in a day that barely functions but has all the basic inputs & user workflows set up to see if I'm in the right ballpark before I burn several days making the real deal... and they say the dreaded words, "Yeah, that's exactly what we want, can you put that in production by end of day, oh and add a background color on this box please?"
    ...
    It's barely even functional enough for a demo why the hell was the background color on a header element in the sidebar a thing you even noticed at this stage?!?!?!



  • @Buddy said:

    If either language had sane parallelism or a better memory model, those other two things would be a lot less significant.

    Parallelism in games is a very hard problem. The best one can usually hope for is a thread for each subsystem with a lot of synchronization code in between.

    @Buddy said:

    You'll switch to c# when they add the using statement?

    I knew someone was going to bring this up. using blocks are cute because they illustrate a case where RAII is superior - file handles, database connections, etc. Imagine that - with all these fancy-schmancy garbage collectors, C# developers have to worry about resource leaks, too! I suppose I could make every such class implement IDisposable, but that feels like a code smell. I would also have to remember to put usings everywhere such a class was instantiated. In C++, I need only have a declaration to accomplish the same thing. And what if I want to destroy the object at a defined point in the future outside the scope of the using?

    @Buddy said:

    In the same post you complain about vendor lock-in.

    Language lock-in and vendor lock-in are two different things. I have the source to every component I use in my project. If Microsoft decides they want to cut C++ support in Visual Studio, I can switch to another compiler and after spending some time cleaning up non-portable code, I'm on my way. If Unity or Unreal or Source go belly-up, I would have to rethink and rewrite major parts of my application.

    If C++ had a stable ABI, it would be easier for other languages to talk to C++ libraries and provide less of an incentive to use C++ except for the most performance-critical areas of an application. So far, it hasn't happened, so that's just wishful thinking on my part.

    @tufty said:

    Oh, and if you're allocating every object on the heap, the garbage collector is smarter than you.

    Yes, which is why stack allocations are favorable wherever possible. If it's a tight loop with hundreds/thousands/millions of iterations, I would imagine the same small region of stack space occupied by the locals would fit neatly in the cache.

    @Buddy said:

    http://www.mono-project.com/Working_With_SGen#Controlling_Collections

    Why is it that I can explain the basic concept of RAII in a single sentence (e.g. "Objects declared within a scope are destroyed at the exit of the scope"*), but that link takes a page to give a high-level summary?

    In all seriousness, a well-written GC is going to be a complex beast. The takeaway I got was that I'm going to have to be mindful of object sizes and tune my allocations, nursery size, etc. to optimize. That feels like tuning SQL queries. I put an index on a column in the WHERE clause in a query against this million-row table - why does the database engine want to do a table scan? The index should be much cheaper!

    @dkf said:

    The downside of the C++ approach is that when things get complicated, debugging it is foully hard.

    Agreed. Errors are much more subtle.

    @dkf said:

    But I'll freely admit that C++ is easier to use than it used to be, provided you don't dive too deep. It used to be horrendous, and now it is only that bad if you decide to start playing Very Clever Template Games…

    I love sifting through walls of cryptic compiler error messages.

    *Bring it, pedantic dickweeds.


  • @Groaner said:

    Why is it that I can explain the basic concept of RAII in a single sentence (e.g. "Objects declared within a scope are destroyed at the exit of the scope"*), but that link takes a page to give a high-level summary?

    How about "Objects that are not accessible are deallocated"? It's shorter than your statement and gives just as much information about garbage collectors as yours gives about RAII.



  • @ben_lubar said:

    How about "Objects that are not accessible are deallocated"? It's shorter than your statement and gives just as much information about garbage collectors as yours gives about RAII.

    Except that it doesn't explain how accessibility is determined, when such a determination is made or with what frequency. A scope can be defined in much less ambiguous terms, even considering exceptions.



  • I like this thread topic. Even if I do acknowledge that I need to take the time to learn C++ properly in the near future due to its ubiquity.

    @Groaner said:

    If C++ had a stable ABI, it would be easier for other languages to talk to C++ libraries and provide less of an incentive to use C++ except for the most performance-critical areas of an application. So far, it hasn't happened, so that's just wishful thinking on my part.

    Isn't this supposedly the purpose behind C++11? It really is the core of the issue here. C++ is great at what it's meant to do. It doesn't play well with others though, so either don't use it, or use it everywhere



  • package main
    
    import (
            "fmt"
    )
    
    // We may as well make it stringly-typed. Yes, that's right. Anything can be a named type.
    type Foo string
    
    func main() {
            // bunch o' variables
            var (
                    pointer1  = new(Foo)
                    pointer2  *Foo
                    pointer3 = NewFalse()
    
                    not_pointer1 Foo
                    not_pointer2 Foo
                    not_pointer3 Foo
            )
    
            // Make 'em all false.
            MakeFalse(pointer1)
            pointer2 = NewFalse()
            MakeFalse(&not_pointer1)
            not_pointer2 = *NewFalse()
    
            fmt.Println(IsFalse(pointer1))
            fmt.Println(IsFalse(pointer2))
            fmt.Println(IsFalse(&not_pointer1))
            fmt.Println(IsFalse(&not_pointer2))
    
            SetGlobal(pointer3)
            not_pointer3 = *IsFalse(Global())
            SetGlobal(&not_pointer3)
    }
    
    // How about a global variable as well? Literally just a variable named "global".
    var global *Foo
    
    // We always need a getter and a setter for a variable that just get and set the variable!
    func SetGlobal(f *Foo) { global = f }
    func Global() *Foo     { return global }
    
    // I need to demonstrate things so here are a few (hopefully) useless functions.
    func PointerSwap(foo *Foo, bar *Foo) {
            tmp := *foo
            *foo = *bar
            *bar = tmp
    }
    
    func MakeFalse(f *Foo) {
            PointerSwap(f, NewFalse())
    }
    
    func NewFalse() *Foo {
            var f Foo = "false"
            return &f
    }
    
    // If f is false, returns f. Otherwise, returns false.
    func IsFalse(f *Foo) *Foo {
            if *f == "true" {
                    MakeFalse(f)
            } else if *f != "FILE_NOT_FOUND" {
                    MakeFalse(f)
            }
            return f
    }
    

    Okay, here's what happens when you ask the compiler what it's doing as far as optimization:

    ./what.go:42: can inline SetGlobal
    ./what.go:43: can inline Global
    ./what.go:46: can inline PointerSwap
    ./what.go:56: can inline NewFalse
    ./what.go:15: inlining call to NewFalse
    ./what.go:24: inlining call to NewFalse
    ./what.go:26: inlining call to NewFalse
    ./what.go:33: inlining call to SetGlobal
    ./what.go:34: inlining call to Global
    ./what.go:35: inlining call to SetGlobal
    ./what.go:53: inlining call to NewFalse
    ./what.go:53: inlining call to PointerSwap
    ./what.go:52: leaking param: f
    ./what.go:53: NewFalse &f does not escape
    ./what.go:62: leaking param: f
    ./what.go:62: leaking param: f
    ./what.go:62: leaking param: f
    ./what.go:13: new(Foo) escapes to heap
    ./what.go:17: moved to heap: not_pointer1
    ./what.go:25: &not_pointer1 escapes to heap
    ./what.go:13: new(Foo) escapes to heap
    ./what.go:24: moved to heap: f
    ./what.go:24: &f escapes to heap
    ./what.go:30: &not_pointer1 escapes to heap
    ./what.go:18: moved to heap: not_pointer2
    ./what.go:31: &not_pointer2 escapes to heap
    ./what.go:26: moved to heap: f
    ./what.go:26: &f escapes to heap
    ./what.go:15: moved to heap: f
    ./what.go:15: &f escapes to heap
    ./what.go:19: moved to heap: not_pointer3
    ./what.go:35: &not_pointer3 escapes to heap
    ./what.go:28: main ... argument does not escape
    ./what.go:29: main ... argument does not escape
    ./what.go:30: main ... argument does not escape
    ./what.go:31: main ... argument does not escape
    ./what.go:42: leaking param: f
    ./what.go:46: leaking param: bar
    ./what.go:46: leaking param: foo
    ./what.go:57: moved to heap: f
    ./what.go:58: &f escapes to heap
    

    And here's the assembly generated by the compiler:

    --- prog list "main" ---
    0000 (/home/user/go/src/what.go:10) TEXT    main+0(SB),$192-0
    0001 (/home/user/go/src/what.go:10) FUNCDATA $0,gcargs·0+0(SB)
    0002 (/home/user/go/src/what.go:10) FUNCDATA $1,gclocals·0+0(SB)
    0003 (/home/user/go/src/what.go:10) TYPE    pointer1+-128(SP){*"".Foo},$8
    0004 (/home/user/go/src/what.go:10) TYPE    pointer2+-96(SP){*"".Foo},$8
    0005 (/home/user/go/src/what.go:10) TYPE    pointer3+-112(SP){*"".Foo},$8
    0006 (/home/user/go/src/what.go:10) TYPE    &not_pointer1+-144(SP){*"".Foo},$8
    0007 (/home/user/go/src/what.go:10) TYPE    &not_pointer2+-136(SP){*"".Foo},$8
    0008 (/home/user/go/src/what.go:10) TYPE    &not_pointer3+-104(SP){*"".Foo},$8
    0009 (/home/user/go/src/what.go:10) TYPE    autotmp_0007+0(SP){*"".Foo},$8
    0010 (/home/user/go/src/what.go:10) TYPE    autotmp_0008+0(SP){*"".Foo},$8
    0011 (/home/user/go/src/what.go:10) TYPE    autotmp_0009+0(SP){*"".Foo},$8
    0012 (/home/user/go/src/what.go:10) TYPE    autotmp_0010+0(SP){*"".Foo},$8
    0013 (/home/user/go/src/what.go:10) TYPE    autotmp_0011+0(SP){*"".Foo},$8
    0014 (/home/user/go/src/what.go:10) TYPE    autotmp_0013+0(SP){*"".Foo},$8
    0015 (/home/user/go/src/what.go:10) TYPE    autotmp_0014+0(SP){*"".Foo},$8
    0016 (/home/user/go/src/what.go:10) TYPE    autotmp_0015+-24(SP){[]interface {}},$24
    0017 (/home/user/go/src/what.go:10) TYPE    autotmp_0016+-120(SP){*[1]interface {}},$8
    0018 (/home/user/go/src/what.go:10) TYPE    autotmp_0017+-88(SP){[1]interface {}},$16
    0019 (/home/user/go/src/what.go:10) TYPE    autotmp_0018+0(SP){[]interface {}},$24
    0020 (/home/user/go/src/what.go:10) TYPE    autotmp_0019+0(SP){*[1]interface {}},$8
    0021 (/home/user/go/src/what.go:10) TYPE    autotmp_0020+-56(SP){[1]interface {}},$16
    0022 (/home/user/go/src/what.go:10) TYPE    autotmp_0021+0(SP){[]interface {}},$24
    0023 (/home/user/go/src/what.go:10) TYPE    autotmp_0022+0(SP){*[1]interface {}},$8
    0024 (/home/user/go/src/what.go:10) TYPE    autotmp_0023+-72(SP){[1]interface {}},$16
    0025 (/home/user/go/src/what.go:10) TYPE    autotmp_0024+0(SP){[]interface {}},$24
    0026 (/home/user/go/src/what.go:10) TYPE    autotmp_0025+0(SP){*[1]interface {}},$8
    0027 (/home/user/go/src/what.go:10) TYPE    autotmp_0026+-40(SP){[1]interface {}},$16
    0028 (/home/user/go/src/what.go:10) TYPE    autotmp_0027+0(SP){*"".Foo},$8
    0029 (/home/user/go/src/what.go:13) MOVQ    $type."".Foo+0(SB),(SP)
    0030 (/home/user/go/src/what.go:13) PCDATA  $0,$16
    0031 (/home/user/go/src/what.go:13) CALL    ,runtime.new+0(SB)
    0032 (/home/user/go/src/what.go:13) PCDATA  $0,$-1
    0033 (/home/user/go/src/what.go:13) MOVQ    8(SP),BX
    0034 (/home/user/go/src/what.go:13) MOVQ    BX,pointer1+-128(SP)
    0035 (/home/user/go/src/what.go:15) MOVQ    $type."".Foo+0(SB),(SP)
    0036 (/home/user/go/src/what.go:15) PCDATA  $0,$16
    0037 (/home/user/go/src/what.go:15) CALL    ,runtime.new+0(SB)
    0038 (/home/user/go/src/what.go:15) PCDATA  $0,$-1
    0039 (/home/user/go/src/what.go:15) MOVQ    8(SP),AX
    0040 (/home/user/go/src/what.go:15) LEAQ    go.string."false"+0(SB),BP
    0041 (/home/user/go/src/what.go:15) MOVQ    AX,DI
    0042 (/home/user/go/src/what.go:15) MOVQ    BP,SI
    0043 (/home/user/go/src/what.go:15) MOVSQ   ,
    0044 (/home/user/go/src/what.go:15) MOVSQ   ,
    0045 (/home/user/go/src/what.go:15) MOVQ    AX,pointer3+-112(SP)
    0046 (/home/user/go/src/what.go:17) MOVQ    $type."".Foo+0(SB),(SP)
    0047 (/home/user/go/src/what.go:17) PCDATA  $0,$16
    0048 (/home/user/go/src/what.go:17) CALL    ,runtime.new+0(SB)
    0049 (/home/user/go/src/what.go:17) PCDATA  $0,$-1
    0050 (/home/user/go/src/what.go:17) MOVQ    8(SP),BX
    0051 (/home/user/go/src/what.go:17) MOVQ    BX,&not_pointer1+-144(SP)
    0052 (/home/user/go/src/what.go:18) MOVQ    $type."".Foo+0(SB),(SP)
    0053 (/home/user/go/src/what.go:18) PCDATA  $0,$16
    0054 (/home/user/go/src/what.go:18) CALL    ,runtime.new+0(SB)
    0055 (/home/user/go/src/what.go:18) PCDATA  $0,$-1
    0056 (/home/user/go/src/what.go:18) MOVQ    8(SP),BX
    0057 (/home/user/go/src/what.go:18) MOVQ    BX,&not_pointer2+-136(SP)
    0058 (/home/user/go/src/what.go:19) MOVQ    $type."".Foo+0(SB),(SP)
    0059 (/home/user/go/src/what.go:19) PCDATA  $0,$16
    0060 (/home/user/go/src/what.go:19) CALL    ,runtime.new+0(SB)
    0061 (/home/user/go/src/what.go:19) PCDATA  $0,$-1
    0062 (/home/user/go/src/what.go:19) MOVQ    8(SP),BX
    0063 (/home/user/go/src/what.go:19) MOVQ    BX,&not_pointer3+-104(SP)
    0064 (/home/user/go/src/what.go:23) MOVQ    pointer1+-128(SP),BX
    0065 (/home/user/go/src/what.go:23) MOVQ    BX,(SP)
    0066 (/home/user/go/src/what.go:23) CALL    ,MakeFalse+0(SB)
    0067 (/home/user/go/src/what.go:24) MOVQ    $type."".Foo+0(SB),(SP)
    0068 (/home/user/go/src/what.go:24) PCDATA  $0,$16
    0069 (/home/user/go/src/what.go:24) CALL    ,runtime.new+0(SB)
    0070 (/home/user/go/src/what.go:24) PCDATA  $0,$-1
    0071 (/home/user/go/src/what.go:24) MOVQ    8(SP),AX
    0072 (/home/user/go/src/what.go:24) LEAQ    go.string."false"+0(SB),BP
    0073 (/home/user/go/src/what.go:24) MOVQ    AX,DI
    0074 (/home/user/go/src/what.go:24) MOVQ    BP,SI
    0075 (/home/user/go/src/what.go:24) MOVSQ   ,
    0076 (/home/user/go/src/what.go:24) MOVSQ   ,
    0077 (/home/user/go/src/what.go:24) MOVQ    AX,pointer2+-96(SP)
    0078 (/home/user/go/src/what.go:25) MOVQ    &not_pointer1+-144(SP),BX
    0079 (/home/user/go/src/what.go:25) MOVQ    BX,(SP)
    0080 (/home/user/go/src/what.go:25) CALL    ,MakeFalse+0(SB)
    0081 (/home/user/go/src/what.go:26) MOVQ    $type."".Foo+0(SB),(SP)
    0082 (/home/user/go/src/what.go:26) PCDATA  $0,$16
    0083 (/home/user/go/src/what.go:26) CALL    ,runtime.new+0(SB)
    0084 (/home/user/go/src/what.go:26) PCDATA  $0,$-1
    0085 (/home/user/go/src/what.go:26) MOVQ    8(SP),AX
    0086 (/home/user/go/src/what.go:26) LEAQ    go.string."false"+0(SB),BP
    0087 (/home/user/go/src/what.go:26) MOVQ    AX,DI
    0088 (/home/user/go/src/what.go:26) MOVQ    BP,SI
    0089 (/home/user/go/src/what.go:26) MOVSQ   ,
    0090 (/home/user/go/src/what.go:26) MOVSQ   ,
    0091 (/home/user/go/src/what.go:26) CMPQ    AX,$0
    0092 (/home/user/go/src/what.go:26) JNE     $1,94
    0093 (/home/user/go/src/what.go:26) MOVL    AX,(AX)
    0094 (/home/user/go/src/what.go:26) MOVQ    &not_pointer2+-136(SP),DI
    0095 (/home/user/go/src/what.go:26) MOVQ    AX,SI
    0096 (/home/user/go/src/what.go:26) MOVSQ   ,
    0097 (/home/user/go/src/what.go:26) MOVSQ   ,
    0098 (/home/user/go/src/what.go:28) MOVQ    pointer1+-128(SP),BX
    0099 (/home/user/go/src/what.go:28) MOVQ    BX,(SP)
    0100 (/home/user/go/src/what.go:28) CALL    ,IsFalse+0(SB)
    0101 (/home/user/go/src/what.go:28) MOVQ    8(SP),CX
    0102 (/home/user/go/src/what.go:28) LEAQ    autotmp_0017+-88(SP),DI
    0103 (/home/user/go/src/what.go:28) MOVQ    $0,AX
    0104 (/home/user/go/src/what.go:28) STOSQ   ,
    0105 (/home/user/go/src/what.go:28) STOSQ   ,
    0106 (/home/user/go/src/what.go:28) LEAQ    autotmp_0017+-88(SP),BX
    0107 (/home/user/go/src/what.go:28) MOVQ    BX,autotmp_0016+-120(SP)
    0108 (/home/user/go/src/what.go:28) MOVQ    autotmp_0016+-120(SP),BX
    0109 (/home/user/go/src/what.go:28) MOVQ    $1,SI
    0110 (/home/user/go/src/what.go:28) MOVQ    $1,DX
    0111 (/home/user/go/src/what.go:28) MOVQ    BX,autotmp_0015+-24(SP)
    0112 (/home/user/go/src/what.go:28) CMPQ    autotmp_0015+-24(SP),$0
    0113 (/home/user/go/src/what.go:28) JNE     $1,115
    0114 (/home/user/go/src/what.go:28) MOVL    AX,(NONE)
    0115 (/home/user/go/src/what.go:28) MOVQ    autotmp_0015+-24(SP),BX
    0116 (/home/user/go/src/what.go:28) MOVQ    $type.*"".Foo+0(SB),AX
    0117 (/home/user/go/src/what.go:28) MOVQ    AX,(BX)
    0118 (/home/user/go/src/what.go:28) MOVQ    CX,8(BX)
    0119 (/home/user/go/src/what.go:28) MOVQ    autotmp_0015+-24(SP),BX
    0120 (/home/user/go/src/what.go:28) MOVQ    BX,(SP)
    0121 (/home/user/go/src/what.go:28) MOVQ    SI,8(SP)
    0122 (/home/user/go/src/what.go:28) MOVQ    DX,16(SP)
    0123 (/home/user/go/src/what.go:28) CALL    ,fmt.Println+0(SB)
    0124 (/home/user/go/src/what.go:29) MOVQ    pointer2+-96(SP),BX
    0125 (/home/user/go/src/what.go:29) MOVQ    BX,(SP)
    0126 (/home/user/go/src/what.go:29) CALL    ,IsFalse+0(SB)
    0127 (/home/user/go/src/what.go:29) MOVQ    8(SP),CX
    0128 (/home/user/go/src/what.go:29) LEAQ    autotmp_0020+-56(SP),DI
    0129 (/home/user/go/src/what.go:29) MOVQ    $0,AX
    0130 (/home/user/go/src/what.go:29) STOSQ   ,
    0131 (/home/user/go/src/what.go:29) STOSQ   ,
    0132 (/home/user/go/src/what.go:29) LEAQ    autotmp_0020+-56(SP),BX
    0133 (/home/user/go/src/what.go:29) MOVQ    BX,autotmp_0019+-120(SP)
    0134 (/home/user/go/src/what.go:29) MOVQ    autotmp_0019+-120(SP),BX
    0135 (/home/user/go/src/what.go:29) MOVQ    $1,SI
    0136 (/home/user/go/src/what.go:29) MOVQ    $1,DX
    0137 (/home/user/go/src/what.go:29) MOVQ    BX,autotmp_0018+-24(SP)
    0138 (/home/user/go/src/what.go:29) CMPQ    autotmp_0018+-24(SP),$0
    0139 (/home/user/go/src/what.go:29) JNE     $1,141
    0140 (/home/user/go/src/what.go:29) MOVL    AX,(NONE)
    0141 (/home/user/go/src/what.go:29) MOVQ    autotmp_0018+-24(SP),BX
    0142 (/home/user/go/src/what.go:29) MOVQ    $type.*"".Foo+0(SB),AX
    0143 (/home/user/go/src/what.go:29) MOVQ    AX,(BX)
    0144 (/home/user/go/src/what.go:29) MOVQ    CX,8(BX)
    0145 (/home/user/go/src/what.go:29) MOVQ    autotmp_0018+-24(SP),BX
    0146 (/home/user/go/src/what.go:29) MOVQ    BX,(SP)
    0147 (/home/user/go/src/what.go:29) MOVQ    SI,8(SP)
    0148 (/home/user/go/src/what.go:29) MOVQ    DX,16(SP)
    0149 (/home/user/go/src/what.go:29) CALL    ,fmt.Println+0(SB)
    0150 (/home/user/go/src/what.go:30) MOVQ    &not_pointer1+-144(SP),BX
    0151 (/home/user/go/src/what.go:30) MOVQ    BX,(SP)
    0152 (/home/user/go/src/what.go:30) CALL    ,IsFalse+0(SB)
    0153 (/home/user/go/src/what.go:30) MOVQ    8(SP),CX
    0154 (/home/user/go/src/what.go:30) LEAQ    autotmp_0023+-72(SP),DI
    0155 (/home/user/go/src/what.go:30) MOVQ    $0,AX
    0156 (/home/user/go/src/what.go:30) STOSQ   ,
    0157 (/home/user/go/src/what.go:30) STOSQ   ,
    0158 (/home/user/go/src/what.go:30) LEAQ    autotmp_0023+-72(SP),BX
    0159 (/home/user/go/src/what.go:30) MOVQ    BX,autotmp_0022+-120(SP)
    0160 (/home/user/go/src/what.go:30) MOVQ    autotmp_0022+-120(SP),BX
    0161 (/home/user/go/src/what.go:30) MOVQ    $1,SI
    0162 (/home/user/go/src/what.go:30) MOVQ    $1,DX
    0163 (/home/user/go/src/what.go:30) MOVQ    BX,autotmp_0021+-24(SP)
    0164 (/home/user/go/src/what.go:30) CMPQ    autotmp_0021+-24(SP),$0
    0165 (/home/user/go/src/what.go:30) JNE     $1,167
    0166 (/home/user/go/src/what.go:30) MOVL    AX,(NONE)
    0167 (/home/user/go/src/what.go:30) MOVQ    autotmp_0021+-24(SP),BX
    0168 (/home/user/go/src/what.go:30) MOVQ    $type.*"".Foo+0(SB),AX
    0169 (/home/user/go/src/what.go:30) MOVQ    AX,(BX)
    0170 (/home/user/go/src/what.go:30) MOVQ    CX,8(BX)
    0171 (/home/user/go/src/what.go:30) MOVQ    autotmp_0021+-24(SP),BX
    0172 (/home/user/go/src/what.go:30) MOVQ    BX,(SP)
    0173 (/home/user/go/src/what.go:30) MOVQ    SI,8(SP)
    0174 (/home/user/go/src/what.go:30) MOVQ    DX,16(SP)
    0175 (/home/user/go/src/what.go:30) CALL    ,fmt.Println+0(SB)
    0176 (/home/user/go/src/what.go:31) MOVQ    &not_pointer2+-136(SP),BX
    0177 (/home/user/go/src/what.go:31) MOVQ    BX,(SP)
    0178 (/home/user/go/src/what.go:31) CALL    ,IsFalse+0(SB)
    0179 (/home/user/go/src/what.go:31) MOVQ    8(SP),CX
    0180 (/home/user/go/src/what.go:31) LEAQ    autotmp_0026+-40(SP),DI
    0181 (/home/user/go/src/what.go:31) MOVQ    $0,AX
    0182 (/home/user/go/src/what.go:31) STOSQ   ,
    0183 (/home/user/go/src/what.go:31) STOSQ   ,
    0184 (/home/user/go/src/what.go:31) LEAQ    autotmp_0026+-40(SP),BX
    0185 (/home/user/go/src/what.go:31) MOVQ    BX,autotmp_0025+-120(SP)
    0186 (/home/user/go/src/what.go:31) MOVQ    autotmp_0025+-120(SP),BX
    0187 (/home/user/go/src/what.go:31) MOVQ    $1,SI
    0188 (/home/user/go/src/what.go:31) MOVQ    $1,DX
    0189 (/home/user/go/src/what.go:31) MOVQ    BX,autotmp_0024+-24(SP)
    0190 (/home/user/go/src/what.go:31) CMPQ    autotmp_0024+-24(SP),$0
    0191 (/home/user/go/src/what.go:31) JNE     $1,193
    0192 (/home/user/go/src/what.go:31) MOVL    AX,(NONE)
    0193 (/home/user/go/src/what.go:31) MOVQ    autotmp_0024+-24(SP),BX
    0194 (/home/user/go/src/what.go:31) MOVQ    $type.*"".Foo+0(SB),AX
    0195 (/home/user/go/src/what.go:31) MOVQ    AX,(BX)
    0196 (/home/user/go/src/what.go:31) MOVQ    CX,8(BX)
    0197 (/home/user/go/src/what.go:31) MOVQ    autotmp_0024+-24(SP),BX
    0198 (/home/user/go/src/what.go:31) MOVQ    BX,(SP)
    0199 (/home/user/go/src/what.go:31) MOVQ    SI,8(SP)
    0200 (/home/user/go/src/what.go:31) MOVQ    DX,16(SP)
    0201 (/home/user/go/src/what.go:31) CALL    ,fmt.Println+0(SB)
    0202 (/home/user/go/src/what.go:33) MOVQ    pointer3+-112(SP),BX
    0203 (/home/user/go/src/what.go:33) MOVQ    BX,global+0(SB)
    0204 (/home/user/go/src/what.go:34) MOVQ    BX,(SP)
    0205 (/home/user/go/src/what.go:34) CALL    ,IsFalse+0(SB)
    0206 (/home/user/go/src/what.go:34) MOVQ    &not_pointer3+-104(SP),CX
    0207 (/home/user/go/src/what.go:34) MOVQ    8(SP),SI
    0208 (/home/user/go/src/what.go:34) CMPQ    SI,$0
    0209 (/home/user/go/src/what.go:34) JNE     $1,211
    0210 (/home/user/go/src/what.go:34) MOVL    AX,(SI)
    0211 (/home/user/go/src/what.go:34) MOVQ    CX,DI
    0212 (/home/user/go/src/what.go:34) MOVSQ   ,
    0213 (/home/user/go/src/what.go:34) MOVSQ   ,
    0214 (/home/user/go/src/what.go:35) MOVQ    CX,global+0(SB)
    0215 (/home/user/go/src/what.go:36) RET     ,
    
    --- prog list "SetGlobal" ---
    0216 (/home/user/go/src/what.go:42) TEXT    SetGlobal+0(SB),$0-8
    0217 (/home/user/go/src/what.go:42) FUNCDATA $0,gcargs·1+0(SB)
    0218 (/home/user/go/src/what.go:42) FUNCDATA $1,gclocals·1+0(SB)
    0219 (/home/user/go/src/what.go:42) TYPE    f+0(FP){*"".Foo},$8
    0220 (/home/user/go/src/what.go:42) MOVQ    f+0(FP),BX
    0221 (/home/user/go/src/what.go:42) MOVQ    BX,global+0(SB)
    0222 (/home/user/go/src/what.go:42) RET     ,
    
    --- prog list "Global" ---
    0223 (/home/user/go/src/what.go:43) TEXT    Global+0(SB),$0-8
    0224 (/home/user/go/src/what.go:43) FUNCDATA $0,gcargs·2+0(SB)
    0225 (/home/user/go/src/what.go:43) FUNCDATA $1,gclocals·2+0(SB)
    0226 (/home/user/go/src/what.go:43) TYPE    ~anon0+0(FP){*"".Foo},$8
    0227 (/home/user/go/src/what.go:43) MOVQ    global+0(SB),BX
    0228 (/home/user/go/src/what.go:43) MOVQ    BX,~anon0+0(FP)
    0229 (/home/user/go/src/what.go:43) RET     ,
    
    --- prog list "PointerSwap" ---
    0230 (/home/user/go/src/what.go:46) TEXT    PointerSwap+0(SB),$0-16
    0231 (/home/user/go/src/what.go:46) MOVQ    foo+0(FP),DI
    0232 (/home/user/go/src/what.go:46) MOVQ    bar+8(FP),DX
    0233 (/home/user/go/src/what.go:46) FUNCDATA $0,gcargs·3+0(SB)
    0234 (/home/user/go/src/what.go:46) FUNCDATA $1,gclocals·3+0(SB)
    0235 (/home/user/go/src/what.go:46) TYPE    foo+0(FP){*"".Foo},$8
    0236 (/home/user/go/src/what.go:46) TYPE    bar+8(FP){*"".Foo},$8
    0237 (/home/user/go/src/what.go:47) NOP     ,
    0238 (/home/user/go/src/what.go:47) MOVQ    (DI),CX
    0239 (/home/user/go/src/what.go:47) MOVQ    8(DI),AX
    0240 (/home/user/go/src/what.go:48) CMPQ    DX,$0
    0241 (/home/user/go/src/what.go:48) JNE     $1,243
    0242 (/home/user/go/src/what.go:48) MOVL    AX,(DX)
    0243 (/home/user/go/src/what.go:48) NOP     ,
    0244 (/home/user/go/src/what.go:48) MOVQ    DX,SI
    0245 (/home/user/go/src/what.go:48) MOVSQ   ,
    0246 (/home/user/go/src/what.go:48) MOVSQ   ,
    0247 (/home/user/go/src/what.go:49) NOP     ,
    0248 (/home/user/go/src/what.go:49) MOVQ    CX,(DX)
    0249 (/home/user/go/src/what.go:49) MOVQ    AX,8(DX)
    0250 (/home/user/go/src/what.go:50) RET     ,
    
    --- prog list "MakeFalse" ---
    0251 (/home/user/go/src/what.go:52) TEXT    MakeFalse+0(SB),$16-8
    0252 (/home/user/go/src/what.go:52) FUNCDATA $0,gcargs·4+0(SB)
    0253 (/home/user/go/src/what.go:52) FUNCDATA $1,gclocals·4+0(SB)
    0254 (/home/user/go/src/what.go:52) TYPE    f+0(FP){*"".Foo},$8
    0255 (/home/user/go/src/what.go:52) TYPE    f+-16(SP){"".Foo},$16
    0256 (/home/user/go/src/what.go:52) TYPE    autotmp_0033+0(SP){*"".Foo},$8
    0257 (/home/user/go/src/what.go:53) LEAQ    go.string."false"+0(SB),BX
    0258 (/home/user/go/src/what.go:53) MOVQ    (BX),BP
    0259 (/home/user/go/src/what.go:53) MOVQ    BP,f+-16(SP)
    0260 (/home/user/go/src/what.go:53) MOVQ    8(BX),BP
    0261 (/home/user/go/src/what.go:53) MOVQ    BP,f+-8(SP)
    0262 (/home/user/go/src/what.go:53) LEAQ    f+-16(SP),BX
    0263 (/home/user/go/src/what.go:53) MOVQ    f+0(FP),DI
    0264 (/home/user/go/src/what.go:53) MOVQ    BX,SI
    0265 (/home/user/go/src/what.go:53) NOP     ,
    0266 (/home/user/go/src/what.go:53) MOVQ    (DI),R8
    0267 (/home/user/go/src/what.go:53) MOVQ    8(DI),DX
    0268 (/home/user/go/src/what.go:53) CMPQ    BX,$0
    0269 (/home/user/go/src/what.go:53) JNE     $1,271
    0270 (/home/user/go/src/what.go:53) MOVL    AX,(BX)
    0271 (/home/user/go/src/what.go:53) NOP     ,
    0272 (/home/user/go/src/what.go:53) MOVSQ   ,
    0273 (/home/user/go/src/what.go:53) MOVSQ   ,
    0274 (/home/user/go/src/what.go:53) NOP     ,
    0275 (/home/user/go/src/what.go:53) MOVQ    R8,(BX)
    0276 (/home/user/go/src/what.go:53) MOVQ    DX,8(BX)
    0277 (/home/user/go/src/what.go:54) RET     ,
    
    --- prog list "NewFalse" ---
    0278 (/home/user/go/src/what.go:56) TEXT    NewFalse+0(SB),$16-8
    0279 (/home/user/go/src/what.go:56) FUNCDATA $0,gcargs·5+0(SB)
    0280 (/home/user/go/src/what.go:56) FUNCDATA $1,gclocals·5+0(SB)
    0281 (/home/user/go/src/what.go:56) TYPE    ~anon0+0(FP){*"".Foo},$8
    0282 (/home/user/go/src/what.go:57) MOVQ    $type."".Foo+0(SB),(SP)
    0283 (/home/user/go/src/what.go:57) PCDATA  $0,$16
    0284 (/home/user/go/src/what.go:57) CALL    ,runtime.new+0(SB)
    0285 (/home/user/go/src/what.go:57) PCDATA  $0,$-1
    0286 (/home/user/go/src/what.go:57) MOVQ    8(SP),AX
    0287 (/home/user/go/src/what.go:57) LEAQ    go.string."false"+0(SB),BP
    0288 (/home/user/go/src/what.go:57) MOVQ    AX,DI
    0289 (/home/user/go/src/what.go:57) MOVQ    BP,SI
    0290 (/home/user/go/src/what.go:57) MOVSQ   ,
    0291 (/home/user/go/src/what.go:57) MOVSQ   ,
    0292 (/home/user/go/src/what.go:58) MOVQ    AX,~anon0+0(FP)
    0293 (/home/user/go/src/what.go:58) RET     ,
    
    --- prog list "IsFalse" ---
    0294 (/home/user/go/src/what.go:62) TEXT    IsFalse+0(SB),$40-16
    0295 (/home/user/go/src/what.go:62) FUNCDATA $0,gcargs·6+0(SB)
    0296 (/home/user/go/src/what.go:62) FUNCDATA $1,gclocals·6+0(SB)
    0297 (/home/user/go/src/what.go:62) TYPE    f+0(FP){*"".Foo},$8
    0298 (/home/user/go/src/what.go:62) TYPE    ~anon1+8(FP){*"".Foo},$8
    0299 (/home/user/go/src/what.go:62) TYPE    autotmp_0035+0(SP){"".Foo},$16
    0300 (/home/user/go/src/what.go:63) MOVQ    f+0(FP),BX
    0301 (/home/user/go/src/what.go:63) NOP     ,
    0302 (/home/user/go/src/what.go:63) MOVQ    (BX),CX
    0303 (/home/user/go/src/what.go:63) MOVQ    8(BX),AX
    0304 (/home/user/go/src/what.go:63) CMPQ    AX,$4
    0305 (/home/user/go/src/what.go:63) JNE     ,324
    0306 (/home/user/go/src/what.go:63) MOVQ    CX,(SP)
    0307 (/home/user/go/src/what.go:63) MOVQ    AX,8(SP)
    0308 (/home/user/go/src/what.go:63) LEAQ    go.string."true"+0(SB),BP
    0309 (/home/user/go/src/what.go:63) LEAQ    16(SP),R8
    0310 (/home/user/go/src/what.go:63) MOVQ    R8,DI
    0311 (/home/user/go/src/what.go:63) MOVQ    BP,SI
    0312 (/home/user/go/src/what.go:63) MOVSQ   ,
    0313 (/home/user/go/src/what.go:63) MOVSQ   ,
    0314 (/home/user/go/src/what.go:63) PCDATA  $0,$40
    0315 (/home/user/go/src/what.go:63) CALL    ,runtime.eqstring+0(SB)
    0316 (/home/user/go/src/what.go:63) PCDATA  $0,$-1
    0317 (/home/user/go/src/what.go:63) MOVBQZX 32(SP),BX
    0318 (/home/user/go/src/what.go:63) CMPB    BX,$0
    0319 (/home/user/go/src/what.go:63) JEQ     ,324
    0320 (/home/user/go/src/what.go:64) MOVQ    f+0(FP),BX
    0321 (/home/user/go/src/what.go:64) MOVQ    BX,(SP)
    0322 (/home/user/go/src/what.go:64) CALL    ,MakeFalse+0(SB)
    0323 (/home/user/go/src/what.go:63) JMP     ,348
    0324 (/home/user/go/src/what.go:65) MOVQ    f+0(FP),BX
    0325 (/home/user/go/src/what.go:65) NOP     ,
    0326 (/home/user/go/src/what.go:65) MOVQ    (BX),CX
    0327 (/home/user/go/src/what.go:65) MOVQ    8(BX),AX
    0328 (/home/user/go/src/what.go:65) CMPQ    AX,$14
    0329 (/home/user/go/src/what.go:65) JNE     ,345
    0330 (/home/user/go/src/what.go:65) MOVQ    CX,(SP)
    0331 (/home/user/go/src/what.go:65) MOVQ    AX,8(SP)
    0332 (/home/user/go/src/what.go:65) LEAQ    go.string."FILE_NOT_FOUND"+0(SB),BP
    0333 (/home/user/go/src/what.go:65) LEAQ    16(SP),R8
    0334 (/home/user/go/src/what.go:65) MOVQ    R8,DI
    0335 (/home/user/go/src/what.go:65) MOVQ    BP,SI
    0336 (/home/user/go/src/what.go:65) MOVSQ   ,
    0337 (/home/user/go/src/what.go:65) MOVSQ   ,
    0338 (/home/user/go/src/what.go:65) PCDATA  $0,$40
    0339 (/home/user/go/src/what.go:65) CALL    ,runtime.eqstring+0(SB)
    0340 (/home/user/go/src/what.go:65) PCDATA  $0,$-1
    0341 (/home/user/go/src/what.go:65) MOVBQZX 32(SP),BX
    0342 (/home/user/go/src/what.go:65) CMPB    BX,$0
    0343 (/home/user/go/src/what.go:65) JEQ     ,345
    0344 (/home/user/go/src/what.go:65) JMP     ,348
    0345 (/home/user/go/src/what.go:66) MOVQ    f+0(FP),BX
    0346 (/home/user/go/src/what.go:66) MOVQ    BX,(SP)
    0347 (/home/user/go/src/what.go:66) CALL    ,MakeFalse+0(SB)
    0348 (/home/user/go/src/what.go:68) MOVQ    f+0(FP),BX
    0349 (/home/user/go/src/what.go:68) MOVQ    BX,~anon1+8(FP)
    0350 (/home/user/go/src/what.go:68) RET     ,
    

    See? Both pointers and non-pointers can be allocated on either the stack or the heap. The compiler handles all that for you. It's not something you need to micro-manage.



  • @ben_lubar said:

    It's not something you need to micro-manage.

    Micromanagement of pointers is the lifeblood of C++ developers. Without that, they would shrivel up and die.


    Filed under: Dessicated Corpse, Pointer Vampires



  • @Groaner said:

    Why is it that I can explain the basic concept of RAII in a single sentence (e.g. "Objects declared within a scope are destroyed at the exit of the scope"*), but that link takes a page to give a high-level summary?

    Probably because most garbage collectors don't deal so much with scope as object lifetimes. So something like this scheme code can't easily define the scope of b or c - both have the potential for escaping the scope of the let that defines them, and its enclosing lambda.

    (lambda (a) 
      (let ([b 1] [c 2])
        ;; do stuff
        (if (null? a) b c)))
    

    Now, you could say

    but that's trivial!

    and you'd be right in this case; b and c are constants that easily fit into a single register, any sane compiler shouldn't be heap allocating them, let alone leaving it to the runtime to garbage collect them.

    Where garbage collection comes in is where a and b are heap allocated objects - scope doesn't apply to them (purposely, to allow them to escape from their creating scope), and that's why I chose scheme as the example - b and c are, in scheme, considered to be heap allocated (even if, in this case, they might eventually be simple constants assigned to registers); lifetime considerations and garbage collection do apply to them. Garbage collection saves you from this (admittedly stupid) C++ which does more or less the same thing

    A* fn(bool a) {
       A* b = new A(1);
       a* c = new A(2);
       // do stuff
       if (a) {
        return c;
       }
       return b;
    }
    

    and again, you might say

    That's pathological. No sane programmer would do that

    and you should be right. But I put it to you that <a @twatwoods pissforce is proof to the contrary.

    Yes, GC is complex, but unless you're on Android it shouldn't be biting you, even for games development. If it is biting you, you're probably, as <a @twatwood might say,

    … doing it wrong



  • @Groaner said:

    I knew someone was going to bring this up. using blocks are cute because they illustrate a case where RAII is superior - file handles, database connections, etc. Imagine that - with all these fancy-schmancy garbage collectors, C# developers have to worry about resource leaks, too! I suppose I could make every such class implement IDisposable, but that feels like a code smell. I would also have to remember to put usings everywhere such a class was instantiated. In C++, I need only have a declaration to accomplish the same thing.

    That's is all very good, but this:

    @Groaner said:

    And what if I want to destroy the object at a defined point in the future outside the scope of the using?

    is supposed to be my bit. Your language is the one that by default automatically destroys objects as soon as they go out of scope.

    The thing is, cleaning up resources is something we're probably always going to have to deal with. The fact that C# can automatically handle one ubiquitous type of cleanup, and then provides a well defined way to mark all remaining objects that will still require cleanup, well, I just don't smell anything wrong with that.

    I feel kind of bad, though, for getting involved in this C vs. C++ vs. C# game though, since the way I understand things...

    @Groaner said:

    The best one can usually hope for is a thread for each subsystem with a lot of synchronization code in between.

    ...all shared-heap-multithread languages are equally fucked.


  • Discourse touched me in a no-no place

    @Groaner said:

    If C++ had a stable ABI, it would be easier for other languages to talk to C++ libraries and provide less of an incentive to use C++ except for the most performance-critical areas of an application. So far, it hasn't happened, so that's just wishful thinking on my part.

    That's one of the main reasons people still prefer plain C; it does have a stable ABI. (Well, it's not too hard to use it to make one.) If you're building an application that doesn't care too much about that, it's not a big deal, but when you're making code that you want your customers to plug bits into, being able to promise that you won't accidentally pull the rug out from under their feet is a Very Big Deal.

    C++ ABI “stability” certainly used to be awful under Linux, where even minor changes would require you to build everything new from scratch. Windows was better, given that the OS vendor wanted to promote people using C++ to write apps for their platform at the time. But this is all from years ago and by hearsay; I was collaborating with someone doing this (and bitching heavily about it) but didn't try it myself.



  • @Buddy said:

    ...all impure shared-heap-multithread languages are equally fucked.

    FTFY


  • Discourse touched me in a no-no place

    @tufty said:

    Garbage collection saves you from this (admittedly stupid) C++ which does more or less the same thing

    The right C++ way to do this would use smart pointers. I believe they use reference counting internally, which is a good simple way to do GC so long as you don't have recursive structures. Structure graphs with loops are death to reference counting.

    std::unique_ptr<A> fn(bool a) {
        std::unique_ptr<A> b(new A(1));
        std::unique_ptr<A> c(new A(2));
        // do stuff
        return (a ? b : c);
    }
    

    This example is brought to you by Google, Stack Overflow and cpprefrence.com


  • Discourse touched me in a no-no place

    @Groaner said:

    In C++, I need only have a declaration to accomplish the same thing.

    But your class needs a destructor unless you're OK with default semantics, which is actually fairly close the weight of a using block.

    using (Foo foo = getTheFoo()) {
        // stuff
    }
    

    vs.

    {
        Foo foo = getTheFoo();
        // stuff
    }
    

    I think I'll call that a wash. (Except I like the lampshading that Foo's destruction is a significant event. C++'s habit of hiding important shit behind insignificant syntax is what really repels me about the language.)



  • Yeah, I know, I even said it was stupid. What's idiomatic in one language is often just plain idiotic in another.

    That said, there's ways of breaking std::unique_ptr<> too - it's not a universal panacea. "Safe" (in terms of memory leakage) C++ programming all too often becomes a horrible mishmash of different memory micromanagement techniques with "unpleasant" impedance mismatches where the worlds collide.

    See std::weak_ptr<>, std::shared_ptr<> and the various other horrible micromanagement shit that C++ programmers have to deal with.
    @dkf said:

    C++'s habit of hiding important shit behind insignificant syntax is what really repels me about the language.)

    Don't even get me started on copy constructors.



  • @dkf said:

    The right C++ way to do this would use smart pointers. I believe they use reference counting internally [...]
    unique_ptr

    unique_ptr doesn't use reference counting though - it's entire purpose is to be the only pointer to a certain object (i.e., it would always have a reference count of 1). In your example, either b or c (depending on a) releases ownership of the pointer to the return value (it does so by using the move-constructor that was introduced in C++11). shared_ptr is the one that uses reference counting.

    @trithne said:

    Micromanagement of pointers is the lifeblood of C++ developers. Without that, they would shrivel up and die.

    QFT.



  • @Groaner said:

    I love sifting through walls of cryptic compiler error messages.

    To remind me that things can get worse, I've kept around a set of diagnostics produced by GCC:

    $ ll -h error.txt
    -rw-r--r--. 1 foo bar 3.4M Oct 18 2007 error.txt

    IIRC it was generated while messing around with Boost.Spirit and the diagnostics relate to a single error.



  • And this thread reminds me why I program in PHP and reiterates everything I have ever said about not being smart enough to do 'real' programming.


  • Discourse touched me in a no-no place

    Arguably (based on traces like that), you're too smart to be doing Real Programming…


  • BINNED

    @Groaner said:

    Are any of these alternatives compatible with the vast amount of libraries that are written in C/C++?

    Haskell and Ada both have FFIs that can use C libraries, but I'm not sure about C++. Maybe @ben_lubar can answer about Go and the others.



  • @dkf said:

    Arguably (based on traces like that), you're too smart to be doing Real Programming…

    yes but I program in fucking PHP ferchrissakes, how smart can I really be? 😛

    In my defence, and not PHP's defence, it provides an interesting economy where the extreme lack of competence means there is a market for actual competence to fix the problems.



  • @Arantor said:

    an interesting economy where the extreme lack of competence means there is a market for actual competence to fix the problems.

    The Software Industry, ladies and gentlemen.



  • @trithne said:

    The Software Industry, ladies and gentlemen.

    Yes, indeed. I am not entirely complaining.


  • ♿ (Parody)

    @trithne said:

    The Software Industry, ladies and gentlemen.

    HGTV has been on in the background here a lot lately, and I can attest that it's also the construction industry.


    Filed Under: not that I needed that channel to know





  • @ben_lubar said:

    http://blog.golang.org/c-go-cgo

    The bad ideas thread is over there.



  • Explain how allowing people who use a C/C++ alternative to use C libraries is a bad idea.


  • ♿ (Parody)

    Reflexive anti-go posting.


  • ♿ (Parody)

    It's an interesting approach. How do they handle stuff like structs? I didn't see anything obvious in the intro or in the comment in the linked C source code.



  • Types are just translated into Go types. So a struct { char *foo; } is translated to a struct { foo *C.char }. Unions aren't supported, but you can write a wrapper function that takes care of that in C and has arguments that aren't unions.



  • @antiquarian said:

    why not find out why the others aren't used more than they are and fix that?

    Popularity is random. It's like going viral.



  • @dhromed said:

    Popularity is random. It's like going viral.

    You mean it's similar to whether or not you get the plague?



  • Except that if they ever find a cure, your life is ruined.

    Actually, I suppose that, given the abundance of existing c(++) code, there will always be a need for good programmers; all we really need is to prevent any further adoption. And really, reducing the amount of noob C and C++ coders is good for everybody. There's just too much undefined behaviour for them to stumble into. So basically, we just need to spread the following facts:

    You are not a {C, C++} programmer if you have not read the standard.



  • @Buddy said:

    Except that if they ever find a cure, your life is ruined.

    Actually, I suppose that, given the abundance of existing c(++) code, there will always be a need for good programmers; all we really need is to prevent any further adoption. And really, reducing the amount of noob C and C++ coders is good for everybody. There's just too much undefined behaviour for them to stumble into. So basically, we just need to spread the following facts:

    <b>You are not a {C, C++} programmer if you have not read the standard.</b>

    Which means they'll just fuck off and become PHP or Node.js programmers. C/C++ is really not the worst environment to be within as a programmer if you've spent any time with those.



  • @Arantor said:

    C/C++ is really not the worst environment to be within as a programmer if you've spent any time with those.

    Here we have experienced linux kernel devs arguing in favor of dereferencing a null pointer (“that's what we've always done”) more than three years after an identical bug introduced a vulnerability into SELinux



  • Too bad a lot of educational institutions - at least where I live - make the mistake of teaching C++ without mentioning anything about the pitfalls.
    It's a huge WTF in my eyes. They should either teach a language like C++ thoroughly or use something less dangerous and inconsistent like Python instead.


  • BINNED

    @Buddy said:

    You are not a {C, C++} programmer if you have not read the standard.

    Some would say this belongs on the evil ideas thread.

    Filed under: Reading documentation is a barrier to coding



  • @Buddy said:

    Here we have experienced linux kernel devs arguing in favor of dereferencing a null pointer (“that's what we've always done”) more than three years after an identical bug introduced a vulnerability into SELinux

    Oh, I'm not saying the group of people that call themselves C programmers is necessarily bad, but even modestly competent C programmers are better than almost the entirety of the populace of PHP programmers.


  • BINNED

    @Arantor said:

    Which means they'll just fuck off and become PHP or Node.js programmers. C/C++ is really not the worst environment to be within as a programmer if you've spent any time with those.

    This is a good thing as it means they won't be doing any system programming, and any damage they do will be confined to whatever applications they are working on, as opposed to libraries, which get used everywhere.



  • @antiquarian said:

    This is a good thing as it means they won't be doing any system programming, and any damage they do will be confined to whatever applications they are working on, as opposed to libraries, which get used everywhere.

    Indeed. I would like to think I am in the top x% of PHP programmers (not that that seems a very high bar) but even I'd be wary of working on system libraries in any language. I do sometimes think these system-level developers do not give their work due level of attention.



  • @Arantor said:

    I would like to think I am in the top x% of PHP programmers

    Just assume x=100 and you're pretty much set.



  • Argh. Maybe it's time to port my stuff to a BSD.


Log in to reply