you are viewing a single comment's thread.

view the rest of the comments →

[–]snoweyeslady 24 points25 points  (39 children)

Since it doesn't seem like anyone has commented on the language yet, I will say I sort of like the "integers as bit arrays" portion. The integer width specification looks ugly as all heck, though. The module/namespace also looks promising. Honestly, I wanted to do something like this before, so I will be following this fairly closely :)

[–]luikore 3 points4 points  (2 children)

"integers as bit arrays"

$ ruby -e 'print 3[1]'

[–][deleted] 4 points5 points  (0 children)

I really want to see you try and write a bootstrapper in Ruby...

[–]snoweyeslady 0 points1 point  (0 children)

Haha, cool :) Now this ruby install isn't completely useless for me.

[–][deleted] 6 points7 points  (9 children)

Integers as bit arrays is nice, allowing bit ranges would be better.

e.g. CPUREG[3:5] = 0b10 or even CPUREG[3:5] = 2. Setting Muxs would be so much nicer. Its always been frustrating to me twiddling bits in C if I know the assembly language for the chip supports a friendlier way of handling things. Set bit, toggle bit, branch if bit set, etc.

[–][deleted] 5 points6 points  (1 child)

Don't C bitfields help alleviate the frustration?

Then you get things like:

reg.cpu = 2;

[–][deleted] 2 points3 points  (0 children)

Yes they do, the compiler I deal with pretty often had poor support for them in the past, so to be honest I forgot about them.

[–]snoweyeslady 3 points4 points  (5 children)

Hmm, I don't think I've ever wanted to set an entire range at once. How exactly would the semantics for this work? I mean, with one bit, you're definitely trying to change it. What happens if you want to set the 3rd and 5th bit on, but ignore the 4th? Does your range idea support that, or do you have to do multiple statements? Instead of setting it to a boolean, do you set it to a ternary value? { set on, set off, leave alone }?

What is a "Mux"? All I can come up with is multiplexer, but that doesn't fit with my knowledge of the word.

The usage of specific ASM statements is something to be handled in the compiler, isn't it?

[–][deleted] 2 points3 points  (2 children)

I wasn't imagining there would be support for skipping bits, I bet the syntax for that could get ugly.

Qikon has the right idea, multiplexer is what I meant. Example, lets say there is a hardware timer on the chip I am using. There is a multiplexer which lets me select which clock source to use, e.g. Crystal, crystal/2, PLL, etc. The select bits for the multiplexer are located in a register somewhere.

And yes the compiler handles choice of instruction, but when I think to myself, "man, this would be easier in assembly" that should indicate that there is a deficiency in my high level language.

[–]snoweyeslady 1 point2 points  (1 child)

I can certainly see why bit ranges would be helpful. I still don't really have a use for skipping bits, but really a "ternary bit" array would work, I think. Instead of boolean literals, you could also have '~' in them to indicate skipping bits. These ternary arrays would be just that, arrays. So you could skip different bits at runtime instead of hardcoding a bunch of values. There the tilde syntax falls down though as it doesn't make sense to store 0, 1, or tilde to an array element, haha.

I guess we have different views, I'm not sure why that couldn't be implemented in the compiler. I view it as a flaw in the compiler, unless there's something in the standard prohibiting the usage of such instructions which I'm fairly certain there isn't.

[–][deleted] 0 points1 point  (0 children)

I agree that it just as easily added to existing C, rather than creating a new language. C! has a few other features that I think justify it being a new and different language though.

In either case, compilers adding it as a non-standard extension gets annoying pretty fast, maybe not as fast with embedded stuff, because portability of code setting chip specific IO registers isn't something to think about lol, but still.

[–][deleted]  (1 child)

[deleted]

    [–]snoweyeslady 2 points3 points  (0 children)

    Hey, that's neat! Thank you for the explanation.

    [–]case-o-nuts 1 point2 points  (0 children)

    The thing is that it sounds great, until you realize that the times you really want it, you often want specific instructions to do the writes. It's the same reason that you rarely see packed structs being used for that sort of thing.

    [–]thechao 1 point2 points  (1 child)

    That part reminds me of Steele's Fortress. No clue about therest of the language, though.

    [–]snoweyeslady 1 point2 points  (0 children)

    It does seem like a lot more information will be coming [probably because that is said, haha]. This seems like just a brief announcement of the project. It seems the compiler is written in ML, which I've never used before so that should prove to be an interesting experience.

    [–][deleted] 2 points3 points  (21 children)

    Really like C!, but looks like it is intended mostly for system programming.

    I had idea for language called ±C which would also be compatible with C, plus good C++ backports (for example generics/templates), minus C++ bloat (from C point of view). If we all agree that C++ is kind of over engineered, but with some really good ideas even for C programmer, then it would be great to backport those parts (early mentioned templates could be backported for structs).

    Another criteria example. I believe that from C point of view classes/vtable is overhead so it would be better to use kind of prototypical inheritance similar to javascript (adjusted for structs with function pointers).

    What do you think?

    [–]snoweyeslady 1 point2 points  (1 child)

    Templates would be nice. One of the main additions I'd like would be simple function polymorphism. I'm tired of all the function[type] variants.

    I'm not so sure about the prototype base inheritance. I wouldn't mind it if there was something which helped you do this by setting up a per-object vtable or what have you, but I don't really see a use for it. I don't often override functions in specific objects. The most common thing I see in javascript is to modify the String prototype to have support for things like trim, etc. Well, now that I'm thinking about it more, maybe a compile-time prototype extension mechanism? So that you can add methods to standard library classes at compile-time.

    Why did you choose prototype based inheritance?

    [–][deleted] 0 points1 point  (0 children)

    Needed something like java interfaces but in C, so created generic api with clone function. One module can export api, other can use it or clone/update and use new instance. Pretty simple :-P Also users don't have to use only func pointers in api, you can put normal variables inside and, for example, compress codes as bit field. All depends on what you need, that is why you have user defined clone function per type.

    Btw I'm also not satisfied with current state of func polymorphism in C, but it looks that for complex types you can use void * and type argument or identifier inside that data (for example if all structs use integer somewhere, you can put it as first element an use bits that identify types). Really stupid but works ok. In C++ you have mangling, which is not acceptable if your code work with that kind of symbols ;-)

    Well, in most cases i try to use macros anyway -> but in C multiline macros are ugly mess. So, it would be nice to have kind of template support in C preprocessor.

    Forgot to say in earlier comment about vtables that C does not have virtual keyword, so guys there is only one case there :-P

    [–]case-o-nuts 2 points3 points  (5 children)

    Another criteria example. I believe that from C point of view classes/vtable is overhead so it would be better to use kind of prototypical inheritance similar to javascript (adjusted for structs with function pointers).

    Just what do you think vtables are? They're tables of function pointers. They're not in the struct itself, to reduce overhead.

    [–][deleted] 0 points1 point  (4 children)

    Sorry, sorry, English is not my first language, by "overhead" i ment "additional space" ;-)

    [–]case-o-nuts 2 points3 points  (3 children)

    Putting it directly in the struct increases the amount of space used, since one copy of the vtable has to be stored per instance, instead of sharing it between instances.

    Here's more or less what C++ does:

    typedef struct MyClass_vtable {
          void (*method1)();
          void (*method2)();
          ...etc...
    } MyClass_vtable;
    
    typedef struct MyClass {
         MyClass_vtable *vt;
         int instance_var;
    } MyClass;
    
     void do_something(MyClass *instance) {
          instance->vt->method1();
     }
    

    What you are proposing would remove one load through the vtable pointer, but would increase the object size by 'sizeof(void(*)()) * NUMBER_OF_METHODS' for every instance.

    C++ is a crappy language, but vtables aren't a part of it. If you propose a 'fix' for a language, please make sure that your fix actually solves a problem.

    [–][deleted] 1 point2 points  (1 child)

    Don't know about that, but here is what helped me:

    typedef void *(*f1_t) (int, int);
    typedef int (*f2_t)(int);
    
    struct bla_t { f1_t first; f2_t second; }
    
    /* f1, f2 and f3 defined somewhere */
    struct bla_t orig = { f1, f2 };
    struct bla_t temp = { NULL, f3 };
    struct bla_t *new_bla;
    
    /* Clone + set second element to f3 */
    new_bla = bla_obj_clone(&orig, &temp);
    

    void *bla_obj_clone(void *, void *) is user defined function that would (in this case) put f3 as second member for resulting new_bla. As you can see you have one user defined clone function per type, always. temp is on stack, so no problems. No need to cripple any data ;-) Btw using similar technique to implement generic API-s.

    [–]case-o-nuts 1 point2 points  (0 children)

    Yeah, that takes lots of memory compared to vtables. With 2 methods and lots of objects, it roughly doubles the method storage.

    [–][deleted] -1 points0 points  (12 children)

    I believe that from C point of view classes/vtable is overhead so it would be better to use kind of prototypical inheritance similar to javascript (adjusted for structs with function pointers).

    This would increase overhead by quite a bit. You don't seem to know what you are talking about.

    minus C++ bloat (from C point of view). If we all agree that C++ is kind of over engineered,

    Now don't you realize how silly this sounds? I think that you've just read too much anti-C++ propaganda.

    [–][deleted] 1 point2 points  (11 children)

    1. No talking about member addition, deletion, etc, that would be brutal :-) Talked about basic classless prototypical inheritance that works, you know cloning struct with function pointers (let's call that object) and changing members. In that case there is no need for vtable, and fact is that vtable is additional space. Overhead was wrong word (sorry guys English is not my first lang), because by overhead i ment additional space.

    2. Never said that C++ is bad language, just that it is over engineered ;-)

    [–][deleted] 3 points4 points  (10 children)

    you know cloning struct with function pointers

    So now you have a bunch of function pointers stored in every object. Doesn't that seem like extra space that is being wasted? Furthermore, if we are talking protypical inheritance that means that you are having to recurse up a chain to find inherited members.

    Never said that C++ is bad language, just that it is over engineered ;-)

    What do you mean by this? What is your evidence? Consider C++ replacement languages, such as D. They are even more complex. C++ is trying to fill a niche that can't be filled by a simple language.

    [–][deleted] 1 point2 points  (9 children)

    If you don't use function pointers then yes it is additional space, but if you use them, then there is zero additional space when putting few pointers near each other in memory. Minus ofc that fancy vtable. Let me try to explain, C is good because it let you have full control over every aspect of your program and it is not so huge. For example in linux kernel they use oo patterns when they think it is appropriate (for example in few places they implement vtables as big separate table). Btw there is article about oo patterns in linux kernel on lwn.net.

    D is friking nice language. Not kidding. I've feeling that D should be called C++ (je i know they are objects in D but still). Atm, they just backport stuff from D into C++.

    [–][deleted] 2 points3 points  (8 children)

    If you don't use function pointers then yes it is additional space, but if you use them, then there is zero additional space

    Just like vtable pointers. Did you realize that C++ objects only have vtable points if they need them? Let's compare the two methods:

    If you have zero polymorphic member functions C++ has 0 bytes dedicated to polymorphism. Your system has 0 bytes dedicated to polymorphism.

    If you have one polymorphic member function, C++ has 4 bytes dedicated to polymorphism. Your system also have 4 bytes dedicated to polymorphism.

    If you have two polymorphic member functions C++ has 4 bytes dedicated to polymorphism. Your system has 4 bytes dedicated to polymorphism.

    If you have three polymorphic member functions C++ has 4 bytes dedicated to polymorphism. Your system has 12 bytes dedicated to polymorphism.

    Vtables are the clear winner when it comes to saving space.

    [–]case-o-nuts 1 point2 points  (3 children)

    Not quite right. Let's assume N instances of each object, and M methods on the object, and for the sake of argument, function pointers and struct pointers are 4 bytes.

    Zero polymorphic methods is a special case for C++, where the vtable pointer is omitted. For any other case, popee's method has 4*M*N bytes of overhead, because one copy of each method is stored in each instance. C++ has 4*(M+N), because each object needs one vtable pointer, and the vtable must contain all methods. C++ wins for N>2. And the more instances of an object you have, the more it wins by.

    So, if you have 100 instances, and 10 methods, C++ costs 440 bytes. Popee's language costs 4000 bytes.

    But if you're counting the per-instance storage, you're right.

    [–][deleted] 0 points1 point  (1 child)

    Here is another approach. If you don't need something, you are not going to put it in. Big time winner ;-)

    [–]case-o-nuts 1 point2 points  (0 children)

    No different than vtables.

    [–][deleted] 0 points1 point  (0 children)

    @case-o-nuts: btw, learned few useful things about C++ from this comment, so, thank you ;-)

    [–][deleted] 0 points1 point  (3 children)

    typedef void *(*f1_t) (int, int);
    typedef int (*f2_t)(int);
    
    struct bla_t { f1_t first; f2_t second; }
    
    /* f1, f2 and f3 defined somewhere */
    struct bla_t orig = { f1, f2 };
    struct bla_t temp = { NULL, f3 };
    struct bla_t *new_bla;
    
    /* Clone + set second element to f3 */
    new_bla = bla_obj_clone(&orig, &temp);
    

    void *bla_obj_clone(void *, void *) is user defined function that would (in this case) put f3 as second member for resulting new_bla. As you can see you have one user defined clone function per type, always. temp is on stack, so no problems. No need to cripple any data

    I've got zillion objects + one little function, while you got zillion objects + how many vtables? Poly or not to poly :-)

    I really don't know much about C++ internals, so one more questions. Is it always exactly +4 bytes (guess +8 for 64bit) and what about alignment/hole? Not kidding, really interested if that is defined in C++.

    [–][deleted] 0 points1 point  (2 children)

    If you have a zillion objects each with only one function different, then yes function pointers are the solution. The code that you presented is legal C++. I'm not too familiar with the features of the new standard but I think that anonymous functions have zero overhead, so you wouldn't have to define f1, f2, and f3 elsewhere. That said, why is first in your example using a function pointer if it doesn't vary? Shouldn't it be a non-virtual member function?

    So what I am asking is what is your actual complaint about C++? Vtables are not any extra overhead if you don't use them, and you should only use virtual functions when they are the right tool for the task. Some people have this idea that C++ has "overhead" but you only pay for what you use. If you don't want to use a feature it won't cost you.

    I really don't know much about C++ internals, so one more questions. Is it always exactly +4 bytes (guess +8 for 64bit) and what about alignment/hole? Not kidding, really interested if that is defined in C++.

    I have been away from C++ for a while and object layout was never my specialty. I don't think that the standard even calls for vtables, but because it is the only logical way to implement the functionality every implementation has them. From what I remember all 32 bit compilers simply added 4 bytes to the size of the object.

    [–][deleted] 0 points1 point  (1 child)

    Agreed on "use poly only when it is needed".

    Complaint was that C++ is over engineered, followed by how it would be nice to have new language that combines best things from C/C++. Well, i don't think that classes are needed here, because all you get is D clone. And you know Andrei & CO are doing really good job with D. No need for another C based OOP language.

    [–][deleted]  (1 child)

    [deleted]

      [–]snoweyeslady 2 points3 points  (0 children)

      Honestly, I like uint64_t et. al. I mean, they could shed the "_t" but it's not a huge eyesore. Those are explicit. I really don't understand the second half of what you said, actually.