Handmade Hero»Forums»Code
65 posts
So Casey thinks C sux?
Replying to longtran2904 (#26006)

The author of C3 language has some pretty cool ideas for a macro system.

https://dev.to/lerno/an-evolution-of-macros-for-c-59b5

https://dev.to/lerno/macros-in-c3-a-status-update-1m1n

Casey had a rant where he also explained the usefulness of iterating over members of a struct.

thx useful stuff;

65 posts
So Casey thinks C sux?
Replying to mmozeiko (#26004)

For my previous serialization example, you need type information to actually iterate over members of structure. Otherwise how you would get each member if you don't know type of structure?

But how is this related to code gen?

Mārtiņš Možeiko
2358 posts / 2 projects
So Casey thinks C sux?
Edited by Mārtiņš Možeiko on
Replying to da447m (#26009)

Because you want all that logic be resolved in compile time (thus the codegen) not runtime. Same concept as C++ templates.

Let's say you have something like this:

int serialize<Type>(Type* obj, uint8* buffer) {
  int count = 0;
  foreach(field in Type.getFields()) {
    if (field == typeof(uint8)) {
      buffer[count++] = field.get(obj);
    } else if (field == typeof(uint16)) {
      uint16 value = field.get(obj);
      buffer[count++] = value & 0xff;
      buffer[count++] = (uint8)(value >> 8);
    } else {
      ... 20 other cases
    }
  }
  return count;
}

(I'm not saying this is the ideal syntax / construction for this, just showing a simple example conceptually)

And let's say you have struct:

struct S {
  uint8 byte;
  uint16 short;
};

What you want when you call serialize<S>(&obj, buffer) is following codegen:

int serialize<S>(S* obj, uint8* buffer) {
  buffer[0] = obj->byte;
  uint16 value = obj->short;
  buffer[1] = value & 0xff;
  buffer[2] = (uint8)(value >> 8);
  return 3;
}

No loops. No if's. No extra comparison & typeinfo. Just raw access to fields, evaluate all the reflection at compile time.

65 posts
So Casey thinks C sux?
Replying to mmozeiko (#26011)

Hi Martins,

if I understood correctly, you want:

1 - compiler unfolds types inside a struct for you, you just write a generic foreach;

2 - naturally if 1) is possible then compiler can unroll the foreach loop, so it becomes just sugary;

3 - in your example with serialization (but really for any other type conversion), compiler will have to identify the container you want to copy stuff, ok, but then will also need to get the proper bytes you want in case of narrowing?

Ok, I get the point I believe, especially why this is better than templating.

[Ok I'll just write down: this is better than templating because, the template still constrains you to write down the exact number of generic fields you access AND their proper names.]

What I don't get, using your example, is why wouldn't you just want the entire struct memcpy() to the byte array?

I get that if you just copy you don't know what the nth to n+kth bytes are, but then when you use the way you want and serialize, don't you also lose this info anyway and will need to write down code to access specific type fields anyway when using that serialized data?

cheers

Mārtiņš Možeiko
2358 posts / 2 projects
So Casey thinks C sux?
Edited by Mārtiņš Možeiko on

What I don't get, using your example, is why wouldn't you just want the entire struct memcpy() to the byte array?

What if you have struct fields that are pointers:

struct Foo {
  size_t count;
  Bar* data;
};

With memcpy this would not serialize properly. In my example I could simply check if field type is pointer and do special code for that.

I get that if you just copy you don't know what the nth to n+kth bytes are, but then when you use the way you want and serialize, don't you also lose this info anyway and will need to write down code to access specific type fields anyway when using that serialized data?

As I said - this is simple example just to show idea. For real serialization you would want extra stuff there - like versioning or field id's, or something similar. Depends on your use case. The point was to show that you can generate different code based on types you use.

65 posts
So Casey thinks C sux?
Edited by da447m on
Replying to mmozeiko (#26015)

Alright Martins,

now I'm at day 206 and 207, now I understood why Casey created the tokenizer and all that, so that he can do what we discussed.

So let me just ask again, just to fix this in my head: the whole point of this is that one can write whatever struct and just parse it at compile time, right?

Doesn't this also require that one needs to create the "accessing" functions (with foreach unrolled) at compile time to extract full advantage?

Mārtiņš Možeiko
2358 posts / 2 projects
So Casey thinks C sux?
Replying to da447m (#26022)

Yes, that's correct. It requires exactly that.

65 posts
So Casey thinks C sux?
Replying to mmozeiko (#26023)

Yes, that's correct. It requires exactly that.

So basically this is a metalanguage that could have been inserted into the compiler as part of the C standard, as you said?

So why not creating a compiler extension among people who want this? (of course I have no idea how difficult this actually is)

Mārtiņš Možeiko
2358 posts / 2 projects
So Casey thinks C sux?
Replying to da447m (#26025)

Because having it in language would be way easier to use & share. Otherwise you would need to install special extensions to use other's code.