3 ms·
I was thinking lately that C is more data-oriented than many. However I'm limited in knowledge mostly to imperative languages. What I mean is that defining arr
by hawski 9y ago
I was thinking lately that C is more data-oriented than many. However I'm limited in knowledge mostly to imperative languages.
What I mean is that defining arrays of structs has very light syntax. For example in Python AFAIK you can't easily do this. You have to use dictionaries (which is cumbersome if you have many rows) or some kind of class/module that will make it even less clear. What Suckless [1] guys are doing where you can use C as configuration language is example of it. Like keybindings configuration [2] in dwm [3]:
static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
/* ... */
};
When I do something in Python I miss this. C++ most likely will require doing some playing around with constructors.
Also with C99 it's only sweeter. When you need you can use designated initializers [4] - putting names of fields or indices of array in initialization list. You can use compound literals [5] to obviate some need for constructors.
[1] https://suckless.org/ https://suckless.org/
[2] https://git.suckless.org/dwm/tree/config.def.h https://git.suckless.org/dwm/tree/config.def.h
[3] https://dwm.suckless.org/ https://dwm.suckless.org/
[4] https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html
[5] https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html
- geofft 9y agoTake a look at https://github.com/python-attrs/attrs https://github.com/python-attrs/attrs which will let you do something like import attr @attr.s class Key(object): modifier = attr.ib() key = attr.ib() function = attr.ib() argument = attr.ib() keys = [ Key(MODKEY, XK_p, spawn, {'v': dmenucmd}), Key(MODKEY|ShiftMask, XK_Return, spawn, {'v': termcmd}), # ... ] which gets you the concise and readable syntax of C structs, while keeping these things as actual attributes as if they were classes (e.g., [key.modifier for key in keys] will work). And you get designated initializers via Python's usual keyword-argument syntax, the ability to specify attr.ib(default=...), and a few other things.
- thechao 9y agoOr make it real data: #define KEY_TABLE(ENTRY) \ ENTRY(MODKEY, key, XK_p, spawn, ...)\ ENTRY(MODKEY|ShiftMask, key, XK_p, spawn, ...)\ Then: #ifdef KEY_TABLE_ENTRY #undef KEY_TABLE_ENTRY #endif//KEY_TABLE_ENTRY static Key keys[] = { #define KEY_TABLE_ENTRY(MOD, KEY, FUN, ARG) { MOD, KEY, FUN, ARG }, KEY_TABLE(KEY_TABLE_ENTRY) #undef KEY_TABLE_ENTRY };
- tom_mellior 9y agoNo need to guard #undef with #ifdef, it's a no-op if the macro is not already defined.
- earenndil 9y agoMost compilers will warn if you #undef something not #defined.
- tom_mellior 9y agoCan you name one and explain how to call it? I can get neither GCC nor Clang to warn about the following file: #undef THIS_VARIABLE_IS_NOT_DEFINED
- earenndil 9y agoNevermind, you're right. The warning I was thinking of was redefinition.
- anyfoo 9y agoWhen I recently used python, after a long absence, I was pleased to discover named tuples: https://pymotw.com/2/collections/namedtuple.html https://pymotw.com/2/collections/namedtuple.html They basically give you the light syntax you were looking for. Related, I was also very pleased to discover mypy for static type checking. I am convinced that it sped up development of my project by an order of magnitude or so. Especially since I was using the also new async/await syntax (something I was also very pleased to discover for my particular project, and it had nothing to do with the web). The use of async/await leads to quite elaborate types, with easily made mistakes that are very painful if only caught at runtime, instead of trivially at compile time. Together, named tuples and static type checking brought in some much missed aspects of C into python.
- yawaramin 9y agoIn Python the equivalent is namedtuples, which IMO is better syntax anyway because you can use named arguments: import collections Key = collections.namedtuple('Key', ['modifier', 'key', 'function', 'argument']) keys = [ Key(modifier=MODKEY, key=XK_p, function=spawn, argument=dmenucmd), Key(modifier=MODKEY|ShiftMask, key=XK_Return, function=spawn, argument=termcmd), Key(modifier=MODKEY, key=XK_b, function=togglebar, argument=0), Key(modifier=MODKEY, key=XK_j, function=focusstack, argument=+1), Key(modifier=MODKEY, key=XK_k, function=focusstack, argument=-1) ]
- tom_mellior 9y agoThat does add a lot of redundant noise on each line, though. I would write this particular case as normal tuples which I would then turn into Keys in a separate step: keys = [Key(*tuple) for tuple in keys] Another possibility is to keep the Key constructor on each line, but to get rid of the keyword arguments, which are not mandatory: >>> Key('a', 'b', 'c', 'd') Key(modifier='a', key='b', function='c', argument='d')