5 ms·
Nice work, maybe. I really don't know if this is a joke. Wow. FWIW, strlen in C is 5 to 7 lines of code depending on how you format your code. See my other com
by burfog 10y ago
Nice work, maybe. I really don't know if this is a joke. Wow.
FWIW, strlen in C is 5 to 7 lines of code depending on how you format your code. See my other comment.
For those who are not experienced C programmers, yes the shorter code is more readable.
- lmm 10y agoresult_size_t and indexed_cata_size_t are generic things that would only need to be written once / in the standard library. (perhaps as macros so that they could be generic i.e. not tied to size_t). So the thing to compare is index_of_first_null_u and strlen4 vs alternate implementation, not the whole set of code that I wrote. And yeah, it's still not nice. In my preferred language it would be something like: def strlen(s: String) = s.cata[size_t] { case Cons(head, tail) => if('\0' == head) 0 else 1 + tail } (yes, a cons list is not the same as an array and this distinction is important at this level - but the logic should look similar) I do think there's value in having a clear separation between what kind of looping you're doing and the per-entry logic (index_of_first_null_u). Is it worth the overhead of doing that in C? Probably not for native C programmers, but if I was writing C to be maintained by functional programmers (or me) then I probably would do it.
- burfog 10y agoI think we would be very unhappy working on the same project. I use functional style in C when it fits... which is rare because most problems are ill-suited to functional programming. The loop on pointer increment and test is completely natural for this problem, as is the pointer math to get the result. This is exactly what the assembly code would do, possibly moving the -1 up to the top and switching from post-increment to pre-increment. (that alternate layout is a C violation that most compilers would accept) You mentioned that C is missing "generics, anonymous functions, multiple return or tail call elimination". Well, not really. generics: use the _Generic keyword anonymous functions: you can autogenerate names via token pasting multiple return: you can return a struct (living w/o auto-unboxing) or pass a pointer for an extra return value tail call elimination: there might not be a language requirement for any particular case, but gcc at least is very good about eliminating tail calls -- that said, code which benefits from this optimization is usually hard for humans to deal with In case you wonder about the C way to count list items... if(!node) return 0; unsigned n = 0; do n++; while(node=node->next); return n; Like that loop? :-) Curly braces are not needed, and an assignment (plain '=') produces an rvalue that can be tested.
- lmm 10y ago> The loop on pointer increment and test is completely natural for this problem, as is the pointer math to get the result. Disagree. "Move the pointer forwards until the value it points to is zero, then measure the distance between where it points and where it started" is a very unnatural way for a human to think about computing the length of a string. The pointer is doing double-duty as a pointer and a counter. It's efficient for the computer, but it's exposing implementation details that don't make a lot of conceptual sense (and don't even match the real implementation these days - modern hardware has to do a lot of work with cache invalidation and the like to maintain the illusion of a unified flat memory space). > This is exactly what the assembly code would do Absolutely - but assembly is optimized for the computer, not the human. > generics: use the _Generic keyword I don't need to do branching based on a finite set of possible types. I want a generic version of result (where value is of the generic type), and I want indexed_cata to accept an operate that returns whichever generic version of result, and return the same type (I made a mistake in my code - it should return size_t rather than int). Can I do that in C? > anonymous functions: you can autogenerate names via token pasting Not good enough I think. I need to be able to create a function at runtime. (I wanted to pass the continuation into operate and then operate can either return directly or call the continuation and return the result of that, rather than have operate return a flag that the caller that indexed_cata checks and loops) > multiple return: you can return a struct (living w/o auto-unboxing) or pass a pointer for an extra return value I passed a pointer to result and returned via that for exactly that reason. Could I have had index_of_first_null_u return a result_size_t instead of accepting a result_size_t* and it would all work? > Like that loop? :-) Curly braces are not needed, and an assignment (plain '=') produces an rvalue that can be tested. I don't. "=" in a loop test is horrible for readability (it looks like an error (and often is), and has very different semantics from mathematical "=" - pascal-style "while(node := node->next)" would be a much clearer syntax), and returning values that are usually discarded is bad practice (I would like discarding values to be a rare event, probably something that can be a compiler warning - ideally I'd like something like a linear type system). The "do" and "while" look like unrelated statements. The if at the top as the special case is ugly and shouldn't be necessary - when a loop is expressed elegantly the zero case should just fall out naturally.
- 10y ago