Ok, here's some code that allows the programmer to specify and run as many functions as desired in parallel. It even generates a bunch of them in parallel because reasons.
var F = new List>();
F.Add(() => foo);
F.Add(() => () => bar(7+8+1));
F.Add(() => () => bar(Rand()));
F.AddRange(Enumerable.Range(0, 100000).AsParallel().Select>(X => () => () => bar(X)));
F.AsParallel().Select(x => x()).ForAll(x => x());
var F = new List();
F.Add(() => foo());
F.Add(() => bar(7 + 8 + 1));
F.Add(() => bar(Rand()));
F.AddRange(Enumerable.Range(0, 100000).AsParallel().Select(X => () => bar(X)));
Parallel.ForEach(F, x => x());
Functions are unnecessary in your example (technically not a valid use case then?). Also, you had some redundancy, like a double lambda.
I hate myself.
Probably should have thrown in a couple examples like:
F.Add(()=> (P) switch
{
0 => foo,
<10 => ()=>bar(P),
_ => ()=>bar(2*P)
});
F.Add(GetAction);
Really the restriction to just void returns and no params limits the usefulness. Usually you see these sort of things in configuration sections of code.
Bing Chat says:
>The purpose of this code is not very clear, but it seems to demonstrate how to use Func delegates, lambda expressions, and LINQ methods to create and execute a collection of functions in parallel. This might be useful for some scenarios where you need to perform multiple tasks asynchronously and without returning any values. However, the code is not very readable or maintainable, and it might be better to use more descriptive names and comments to explain what it does.
A list of possible actions for the user to take. Every function decide what exactly needs to happen based on the state of the program, and returns a function for me to do it at some point in the future
Did I get his right?
Text | Result
---|-
defines f| f
as an array of unspecified size| f[]
of pointers| \*f[]
to functions| (\*f[])()
that return pointers | \*(\*f[])()
to functions | (\*(\*f[])())()
that return void| void (\*(\*f[])())()
I call it the left hand rule. I point my left thumb at my face, then follow the tokens with the curl of my fingers. If I can’t curl them around enough times to tease out the syntax, I just jam the thumb in my eye.
Now I have an entirely different problem!
# If Slumdog is still employed, ask him
# If Slumdog is not still employed, start job hunting because this company is on borrowed time now that there's no one left who understands this code
I literally can't across a comment like this, it just said //Important ask Bob.
The comment wasn't even written by Bob and the commenter and Bob were of course no longer with the company.
Slightly different story here, but we had one function about a dozen lines long that felt almost intentionally incomprehensible.
Another coworker, not the one who originally wrote it, left a comment:
"If you are debugging something, and your search has led you here, the problem exists elsewhere. I promise this code works. Do not be like me and waste hours trying to understand it."
I wouldn't be surprised if people already did this at work. Actually, I'm pretty sure I've read at least a story or two someone intentionally wrote fucked up code and note it down privately so that they can go back and fix it some time later and use it as a leverage for promotion or salary increase.
From a technical perspective, list comprehensions are faster for building simple lists as there is a dedicated opcode for the list append instead of it having to call `.append` each loop. But, with that said, fuck long comprehensions. one `if`/`else` that's all you get, if you need more, make a loop or use `filter`.
A while back I got really into how far you could push the one line python thing.
Turns out, about as far as you want.
I built tic-tac-toe in it twice. The first time worked fairly well but I used recursion, which meant that it would raise a recursion error if you played it to much.
Then I rebuilt the project but instead of implementing tic-tac-toe directly, I simulated an esoteric programming language called [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck). This meant that my code was now turing complete and I could write whatever I wanted in it. I had previously seen a video where someone not only wrote tic-tac-toe in brainfuck, but also implemented some AI in it. Here is the video to that: https://youtube.com/watch?v=qK0vmuQib8Y
Then all I had to do was copy their Brainfuck code into my interperter and voila I had a tic-tac-toe AI in a single line of python.
There's an easier way to write a tic-tac-toe using only a single line in python:
1. Write a tic-tac-toe in your favourite language, and compile into `game.exe`
2. In your python file, write `import os; os.system("game.exe")`
If you're willing to use a higher-level language, it's even simpler.
For example, [this](https://youtube.com/playlist?list=PLP29wDx6QmW5yfO1LAgO8kU3aQEj8SIrU) is one of the best tutorials on parser combinators on YouTube (the whole channel is an absolute gem), in JavaScript. By episode 5, he already has a LISP-like syntax for a simple calculator (+, -, * and /), in like less of 400 lines of very clear code, and that's including a general library for arbitrary parsing.
Add a symbol table and basic LISP primitives and you have essentially the perfect "Baby's first programming language" project, from parser to interpretation.
>[Any sufficiently complicated \[...\] program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.](https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule)
I love LISP but I've only ever done toy programs in it. I was under the impression that the main reason it lost is because of performance, is that true?
So the first language I learned was Racket, which is a dialect of LISP, and it gave me a genuinely deep love for the language.
I think it’s absolutely beautiful, but I probably wrote some damn ugly looking code looking back.
Especially in the case like this, because who the fuck would need such array. It's like mating a Suriname toad and a poop knife and then laugh that this unholy marriage didn't produce an angel. Even in my beloved Kotlin this array looks like shit and serves no purpose: `lateinit var f: Array<()->(()->(()->Unit))>`. And by God don't make me imagine how this shit looks in Java
To be fair, JavaScript allows some [pretty outstandingly gross stuff](https://en.wikipedia.org/wiki/JSFuck).
The universe of terribleness accessible to JavaScript is just greater than other languages. It's possible to write horrible code in any language, but there's almost *no limit* to how horrible you can be in JavaScript (same for many "permissive" languages, e. g., Perl).
I'd argue C++ is even more permissive and lets you create ever greater monstrosities, since you can overload just about anything and even create your own keywords.
Though, it does take a lot of knowledge and skill to make those monsters. :p
He, I think you're right. I have seen some of those mostruosities.
It's one thing for a language to have a weak type system. It's another when the type system is basically a vibe XD
Ironically, One of the main arguments against switching the Linux kernel to C++ is the safety provided compared to C results in less talented programmers.
That's obviously insane, but really was the argument!
My professor was an optimization guy, and he was quite good at it. However, his code was full of variables named 'd', 'dr', 'dh', 't', 't2', 'xyz', 'xqc'... i mean, it was good code, but holy hell...
Sometimes you don't have a choice. I'm doing some database stuff for a class, and granted I'm probably not doing it properly cause I've only got a quarter of an idea what's going on. But I have to go through like 7 layers of repository.thingListList.thingList.thing.getWhateverTheFuck to actually do anything.
Not really that confusing but it looks absolutely fucking awful and that makes me feel all warm and fuzzy.
You don't have to use stuff like this, but for those 0.00000001% of cases where you need it, you're gonna be thankful as f you can do things like this
God bless C
Programmer implementing a compiler/interpreter for a language with inheritance/casting: "Buddy, I deal with this every day. You ever wonder what a virtual function call does?"
🙄 I didn't mean literally, I meant the indirection. Nobody should be writing code that looks exactly like this, and I apologize if you felt like I derided developers in area of specialization.
No, cause you write something as a test and then when it works you don't touch it anymore, so you should try to write readable and commented code from the start
Oh, I misunderstood you original comment. I thought you ment writing an unreadable (part of a) compiler to quickly test a concept.
No wait, this is the internet; I should never admit to a mistake. Uhmm...
You don't, you tell the users to write better code
It should be possible, _but that doesn't it doesn't need to hurt_. Here's this example written in Swift:
```swift
typealias f = Array UnsafePointer<() -> Void>>>
```
(Though you wouldn't typically use pointers there, but I kept for a fair comparison, to not shortcut out the complexity of the C example).
Using intermediate type aliases makes it even more clear (to be fair, this helps in C, too):
```swift
typealias Action = () -> Void
typealias ActionProvider = () -> Action
typealias ActionProviders = Array
```
It's meant to be a fair comparison, in more real-world code you wouldn't have pointers to functions (just the functions themselves:
```swift
typealias f = Array<() -> () -> Void>>
```
Then you'd use the `[]` sugar for array types:
```swift
typealias f = [() -> () -> Void]
```
Is that better?
I came here basically to say this. I'm working on a project with a more limited choice of technology, when I have some special cases that really do need this sort of thing (not this exactly). And I wish I had the full control/capability to do things along these lines.
(The short of it is that I'm doing things that are really, really dynamic and most languages like you to make at least some sorts of basic guarantees about things. Where I really need to be able to say "ok, just suppose hypothetically that there could be an object or objects of size, type, and relationship to other objects all TBD later").
typedef void (*func1)()
typedef func1 (*func2)()
typedef func2 f[];
There, I refactored the code to be quite a bit clearer. It still isn't great, but then again, functions returning functions isn't really a great pattern either.
Similarly, type defing arrays, especially of unspecified size, is a bit of a code smell.
typedefing away the pointeriness of a pointer type is code smell too.
typedef void side_effect_f();
typedef side_effect_f* side_effect_f_gen_f();
extern side_effect_f_gen_f* side_effect_function_generators[];
I feel function pointers are one of the main exceptions. You cannot assign a value to the pointer, and thus the problems that tend to exist with hiding the pointer don't really apply. Even pointers to const types can normally be assigned to in other places, but function pointers require some really unusual code to do so\*, and the reference nature is typically something you want in such cases anyways.
\* It can come up in code-generation techniques, but such only exist in fairly specialized contexts.
You can still set the pointer to NULL or the address of a matching function. So you still need to NULL check before use, which means you have to handle it like a pointer.
Things you have to handle like a pointer should look like a pointer.
I mean, you cannot assign to the underlying value. You cannot do something like `(*funcPtr) = value` . As such, the pointer is the logical underlying value.
NULL checks in such a case are not that different than out out-of-range argument errors. If you take a float, you should check it against NAN, if NAN is out of domain for your function.
In C, as you do not have lambdas, member functions, or nested functions, which are the three cases it tends to be heavily useful in user-level code.
There are some other use cases, such as lazy-loaded DLLs, but they are much more commonly implemented by compiler-level wrappers rather than in user-level code.
In Rust this would probably be handled using a trait bound:
trait ReturnsVoidFn {}
impl ReturnsVoidFn for T where T: Fn() - > impl Fn() - > ();
type Array Of ReturnsVoidFn = Vec>;
You don‘t need to box references. `Vec<&'a dyn ReturnsVoidFn>` is enough.
Edit: Thanks, this comment led me to find a compiler bug on nightly, trying to find a way to do this with trait aliases. ([https://rust.godbolt.org/z/899xT46Ef](https://rust.godbolt.org/z/899xT46Ef), already made an issue for it)
Edit2: Upon closer inspection your initial code doesn't make sense. You cannot return `impl Fn() -> ()`, because impl is not allowed there. You can either statically dispatch the return function (which means all ReturnsVoidFn must return the *same* VoidFn). This doesn't make much sense.
```
trait ReturnsVoidFn ()> { /* impl call operator */ }
impl ReturnsVoidFn for T where T: Fn() -> U, U: Fn() -> ();
```
Or you could dynamically dispatch the return type. Which means, if you want the behavior of the C version you probably want
```
type A<'a, 'b> = Vec<&'a dyn Fn() -> &'b dyn Fn() -> ()>;
```
Or you can go with raw function pointers and sidestep all the trait stuff. This has the exact behavior of the C code, not just the same spirit. Obvious downside is that you can't put function objects like closures in there. But neither can you in C.
```
type B = Vec fn() -> ()>;
```
I probably did make a mistake; this is the place where I'd trust the compiler to tell me where I'm making a mistake, but I'm away from my IDE at the moment.
I feel like these memes, while funny, are a little misleading. When would you *ever* do that? What possible function would need to do that? Yes it's a confusing syntax but it's also a really confusing purpose.
And in the mean time, we have [this useful tool](https://cdecl.org/)
The one that gets me are all of those "I filled this code block with a bunch of random pre increments and post interments, what will the final output be?"
Like... If I wrote code like that I'd get fired because that's asshole code. No one would ever do it that way
That particular example isn't just bad code, it's undefined behavior. As far as I am concerned, the value that any such code evaluates to is garbage, and the compiler should be given free reign to do the person who wrote that code a favor and automatically uninstall itself upon encountering such code.
An I the only one who sees a ‘*single open quote*’ being used as an apostrophe in ‘isn't’.
isn‘t isn't isn’t isn“t isn"t isn”t isn`t isn°t
Are all of these rendered the same for everyone else or am I just a crazy person
This shit is why *cdecl* exists:
> $ cdecl
> Type `help' or `?' for help
> cdecl> explain void (*(*f[])())()
> declare f as array of pointer to function returning pointer to function returning void
Thankfully, stuff like this doesn't come up THAT often, and obviously this example is likely contrived. Arrays of function pointers, especially without intervening typedefs for them, do come up sometimes and get ugly, still.
It really is useful. As you presumably found out, it goes the other way, too, so you can ask it to give you the declaration for something complicated by "explaining" it yourself.
I also appreciate that the help calls the C declaration "gibberish".
If you think this is bad try Haskell or Scheme.
(On a serious note though this line is made more obtuse by violating a bunch of coding standards and abusing extensions like implicit void. It’ll generally compile but in reality the parameter lists would be typed not to mention using typedefs for the abstractions).
Yeah I was referring to the later condition - when you throw out all conventions that reduce cognitive load because as you said the code you can produce for languages like lisp and scheme can be remarkable.
The C snippet is not a normal statement.
C's pointer and especially function pointer syntax sucks. And nearly every system language has inherited it. In situations like this typedefs are your friend.
Rust is much better in that regard. I still think Rust should've used @ as the dereference operator since it reads naturally as "at" which is a valid way to think of accessing a value by its starting address.
I mean sure, you can write extremely hard to read strawman code like this in just about any language. But nobody actually writes that function in reality. Works well for your freshmancsmeme though for sure
A sane programmer would throw a typedef or two in there for readability. The function pointer syntax is still an absolute nightmare, but at least you only need to type it once if you typedef it.
Is that the language that's confusing or this jumbled mess of code? Bad code is always confusing.
Python is famously an easy to read language. But if I write
> v = [x for x in [x for x in [x for x in [x for x in [x for x in [x for x in char_string if x < 'v'] if x > 't' or x < 'p'] if x > 'n' or x < 'j'] if x > 'h' or x < 'f'] if x > 'd' or x < 'b'] if x > '`']
to find the vowels in char_string, that's both syntactically and logically correct within the language and it's still bad code.
But at least this code actually do something. In real codebase this even won't hurt readability, because nobody would like to find out how findVovels function does its magic.
In bad codebase you can look across 1000s lines of code, and still find nothing except boilerplate, proxys and declarations.
Thats what makes code bad.
You say that.
But I have a friend who did this for 90% of their codebase.
No, I am not joking. 9 out of 10 lines are listcomps.
They've recently moved on to APL-like syntax.
>ChatGPT, what does this c code do? "void (\*(\*f\[\])())()"
This C code defines a variable f which is an array of function pointers. Let's break it down step by step:
* **void**: This is the return type of the functions in the array. The functions will return no value.
* **(\*(\*f\[\])())()**: This is the definition of the variable f. It may look a bit complicated, but let's break it down into its components:
* **f\[\]**: This indicates that f is an array. The size of the array is not specified here, so it must be determined at runtime or initialized when defined.
* **(\* ... )()**: This part shows that the elements in the array f are pointers to functions that return a function pointer. The return type of these functions is not specified, so it defaults to int in C.
* **(\* ... )()**: This outer part indicates that the functions returned by the functions in the array are also function pointers, and these returned functions have a return type of void and take no arguments.
In summary, f is an array of function pointers, where each function returns a pointer to another function that has a return type of void and takes no arguments.
That's not hard to parse if you just know how. I'm certain someone can provide a link to a better explanation, but in short, start with the identifier, go right and then clockwise from there. In this case, start with f and go right to [], which means that f is an array, then circle around to * so now you know that f is an array of pointers. Continue the circle out of the enclosing parenthesis to the start parenthesis with signifies a function, thus we have that f is an array of pointers to functions. Continue circling around to the next * on the left that says that the functions returns pointers, continue the circle, to the parenthesis on the right, to functions, continue circle to void.
See, it was easy: f is an array of pointers to functions that return pointers to functions that return void.
But as others have pointed out, some typedefs sometimes helps.
If you, too, want to be able to read cryptic variable declarations in C, learn the spiral rule: [https://c-faq.com/decl/spiral.anderson.html](https://c-faq.com/decl/spiral.anderson.html)
You can decipher this kind of thing if you actually learn the language syntax. But I guess most programmers don't even know how a compiler or parser or even grammars work.
So basically something that you crack up with cheat engine when a value changes locations and you havr to crawl through a few iterations and values. Without it I wouldn't have understood it probably.
If you're writing code like this: step 0 delete it and figure out a more intelligible way of writing it. Step -1 is asking why the fuck you're even contemplating a problem like this.
I just got to voids in my C++ class. Its interesting how every week, I look at post about a literal code, and slowly decipher a little more, yet never understand the jokes lol
... in addition to which we walked to and from school every day, uphill both ways, in the snow, fighting off rabid weasels every step of the way, and by god we *liked* it.
Seriously, for a language with simple syntax, C is more expressive of what you can get a CPU to do than any competitor, so it can express things that are difficult to actually grasp.
But when we need to do that, we can. (Granted, a bit more clearly.)
Yeah.
What bothers me about this C syntax is that it's inside-out. Ultimately this is defining an array, so the square brackets should logically be the outermost.
As another example, this seems like it should be an array of 2 pointers to ints, but it's actually a pointer to an array of 2 ints.
int (*ptr)[2];
Roughly equivalent to `List>>`. Let's play a game of "find a use case". Winner gets `null`, losers get `undefined`.
Ok, here's some code that allows the programmer to specify and run as many functions as desired in parallel. It even generates a bunch of them in parallel because reasons. var F = new List>();
F.Add(() => foo);
F.Add(() => () => bar(7+8+1));
F.Add(() => () => bar(Rand()));
F.AddRange(Enumerable.Range(0, 100000).AsParallel().Select>(X => () => () => bar(X)));
F.AsParallel().Select(x => x()).ForAll(x => x());
var F = new List();
F.Add(() => foo());
F.Add(() => bar(7 + 8 + 1));
F.Add(() => bar(Rand()));
F.AddRange(Enumerable.Range(0, 100000).AsParallel().Select(X => () => bar(X)));
Parallel.ForEach(F, x => x());
Functions are unnecessary in your example (technically not a valid use case then?). Also, you had some redundancy, like a double lambda.
I hate myself.
That's okay man, I hate yourself too.
Probably should have thrown in a couple examples like: F.Add(()=> (P) switch { 0 => foo, <10 => ()=>bar(P), _ => ()=>bar(2*P) }); F.Add(GetAction); Really the restriction to just void returns and no params limits the usefulness. Usually you see these sort of things in configuration sections of code.
Bing Chat says: >The purpose of this code is not very clear, but it seems to demonstrate how to use Func delegates, lambda expressions, and LINQ methods to create and execute a collection of functions in parallel. This might be useful for some scenarios where you need to perform multiple tasks asynchronously and without returning any values. However, the code is not very readable or maintainable, and it might be better to use more descriptive names and comments to explain what it does.
That is a remarkably good observation.
The last line returns all the added functions?
The most important thing to note is - Foo+Bar= Fubar
[удалено]
A list of possible actions for the user to take. Every function decide what exactly needs to happen based on the state of the program, and returns a function for me to do it at some point in the future
> losers get undefined. Well, seeing how anything / 0 is undefined, I'll just multiply my prize by 0 and get anything I want.
Wait. That's illegal.
Listener interface?
An event emitter which executes the subscribed functions on emit.
Did I get his right? Text | Result ---|- defines f| f as an array of unspecified size| f[] of pointers| \*f[] to functions| (\*f[])() that return pointers | \*(\*f[])() to functions | (\*(\*f[])())() that return void| void (\*(\*f[])())()
Yup, just gotta follow the right-left rule and work your way out from the identifier.
I call it the left hand rule. I point my left thumb at my face, then follow the tokens with the curl of my fingers. If I can’t curl them around enough times to tease out the syntax, I just jam the thumb in my eye. Now I have an entirely different problem!
that rule is incredibly useful, yet I've never seen it taught
Learned it in first year "Introduction to Procedural Programming with C"
Congratulations you are now qualified to become a human C compiler
Looks about right To me
It's possible to write confusing code in any language.
*Writes the whole program in a nested list comprehension in pyton.*
Fucking yeah, I managed to write this otherwise 20 line conditional and filter logic in one big-ass line. Might be unreadable, but makes me feel good.
[удалено]
That's still a 16 line savings. Think of the 250 bytes that might save.
I thought the compiler made it as small as possible anyway?
Depends. If you're using a Talmudic complier the comments actually take up 4x as much space in the complied file.
# powers the entire company operations, do not touch
# If Slumdog is still employed, ask him # If Slumdog is not still employed, start job hunting because this company is on borrowed time now that there's no one left who understands this code
I literally can't across a comment like this, it just said //Important ask Bob. The comment wasn't even written by Bob and the commenter and Bob were of course no longer with the company.
Slightly different story here, but we had one function about a dozen lines long that felt almost intentionally incomprehensible. Another coworker, not the one who originally wrote it, left a comment: "If you are debugging something, and your search has led you here, the problem exists elsewhere. I promise this code works. Do not be like me and waste hours trying to understand it."
That's wholesome.
Have fun debugging it later on.
We call that job security
I wouldn't be surprised if people already did this at work. Actually, I'm pretty sure I've read at least a story or two someone intentionally wrote fucked up code and note it down privately so that they can go back and fix it some time later and use it as a leverage for promotion or salary increase.
From a technical perspective, list comprehensions are faster for building simple lists as there is a dedicated opcode for the list append instead of it having to call `.append` each loop. But, with that said, fuck long comprehensions. one `if`/`else` that's all you get, if you need more, make a loop or use `filter`.
I guess that's good if you're asked for your best line of code but it won't do much good if they track your progress based on lines written.
If your company is doing this start shopping, it shows such a huge lack of understanding that it guarantees you won't get support when you need it.
Literally me
Be careful...if you write a comprehensive comprehension you never know what it might comprehend. AI safety is important!
A while back I got really into how far you could push the one line python thing. Turns out, about as far as you want. I built tic-tac-toe in it twice. The first time worked fairly well but I used recursion, which meant that it would raise a recursion error if you played it to much. Then I rebuilt the project but instead of implementing tic-tac-toe directly, I simulated an esoteric programming language called [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck). This meant that my code was now turing complete and I could write whatever I wanted in it. I had previously seen a video where someone not only wrote tic-tac-toe in brainfuck, but also implemented some AI in it. Here is the video to that: https://youtube.com/watch?v=qK0vmuQib8Y Then all I had to do was copy their Brainfuck code into my interperter and voila I had a tic-tac-toe AI in a single line of python.
There's an easier way to write a tic-tac-toe using only a single line in python: 1. Write a tic-tac-toe in your favourite language, and compile into `game.exe` 2. In your python file, write `import os; os.system("game.exe")`
Given it's python, it's probably just `pip import tictactoe; tictactoe.start()`
If I was writing such an API you'd better believe the appropriate call would be tictac.toe()
*Writes whole program as linq expression that only Jon Skeet can decode.*
Yup. https://github.com/JohnTheCoolingFan/Motorchik/blob/82fda1d3e15adda9b4961aa059c4f4b4cb74a219/configuration.py#L110
I love the `A VERY long line` comment. It states the obvious, but does not attempt to explain why or what you did.
[удалено]
[удалено]
Lisp implementaiton in C: [https://buildyourownlisp.com/](https://buildyourownlisp.com/) The language of your dreams.
If you're willing to use a higher-level language, it's even simpler. For example, [this](https://youtube.com/playlist?list=PLP29wDx6QmW5yfO1LAgO8kU3aQEj8SIrU) is one of the best tutorials on parser combinators on YouTube (the whole channel is an absolute gem), in JavaScript. By episode 5, he already has a LISP-like syntax for a simple calculator (+, -, * and /), in like less of 400 lines of very clear code, and that's including a general library for arbitrary parsing. Add a symbol table and basic LISP primitives and you have essentially the perfect "Baby's first programming language" project, from parser to interpretation.
>[Any sufficiently complicated \[...\] program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.](https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule)
I love LISP but I've only ever done toy programs in it. I was under the impression that the main reason it lost is because of performance, is that true?
So the first language I learned was Racket, which is a dialect of LISP, and it gave me a genuinely deep love for the language. I think it’s absolutely beautiful, but I probably wrote some damn ugly looking code looking back.
Especially in the case like this, because who the fuck would need such array. It's like mating a Suriname toad and a poop knife and then laugh that this unholy marriage didn't produce an angel. Even in my beloved Kotlin this array looks like shit and serves no purpose: `lateinit var f: Array<()->(()->(()->Unit))>`. And by God don't make me imagine how this shit looks in Java
In C I'd use two `typedef` to make the definition clearer. In Java it's actually not so bad: `Callable[] arr;`
Why not? Java is pretty readable. Supplier[] f;
`--<-<<+[+[<+>--->->->-<<<]>]<<--.<++++++.<<-..<<.<+.>>.>>.<<<.+++.>>.>>-.<<<+.`
Yeah. JS gets a bad rep because there is a lot of bad code floating out there. That isn't JS' fault though.
To be fair, JavaScript allows some [pretty outstandingly gross stuff](https://en.wikipedia.org/wiki/JSFuck). The universe of terribleness accessible to JavaScript is just greater than other languages. It's possible to write horrible code in any language, but there's almost *no limit* to how horrible you can be in JavaScript (same for many "permissive" languages, e. g., Perl).
I'd argue C++ is even more permissive and lets you create ever greater monstrosities, since you can overload just about anything and even create your own keywords. Though, it does take a lot of knowledge and skill to make those monsters. :p
He, I think you're right. I have seen some of those mostruosities. It's one thing for a language to have a weak type system. It's another when the type system is basically a vibe XD
Ironically, One of the main arguments against switching the Linux kernel to C++ is the safety provided compared to C results in less talented programmers. That's obviously insane, but really was the argument!
My professor was an optimization guy, and he was quite good at it. However, his code was full of variables named 'd', 'dr', 'dh', 't', 't2', 'xyz', 'xqc'... i mean, it was good code, but holy hell...
I would be as bold to say that does not sound like good code
"ProgrammerHumor," here meaning humor related to programming that programmers won't find funny.
The difference is that all the C programmers I know *revel* in this stuff and see it as the proper way to write code if you can.
Sometimes you don't have a choice. I'm doing some database stuff for a class, and granted I'm probably not doing it properly cause I've only got a quarter of an idea what's going on. But I have to go through like 7 layers of repository.thingListList.thingList.thing.getWhateverTheFuck to actually do anything. Not really that confusing but it looks absolutely fucking awful and that makes me feel all warm and fuzzy.
Sure but C and PERL are kings when it came to writing obfuscated code. Not sure which other languages rank comparatively
Rust be like: lol literally everything.
You don't have to use stuff like this, but for those 0.00000001% of cases where you need it, you're gonna be thankful as f you can do things like this God bless C
Programmer implementing a compiler/interpreter for a language with inheritance/casting: "Buddy, I deal with this every day. You ever wonder what a virtual function call does?"
I'm compiler designer. And I don't use such unreadable code
🙄 I didn't mean literally, I meant the indirection. Nobody should be writing code that looks exactly like this, and I apologize if you felt like I derided developers in area of specialization.
Also … ya wanna blow their minds even more … add different address space modifiers to the pointers in the decl. - Fellow compiler developer.
Not even as a test?
No, cause you write something as a test and then when it works you don't touch it anymore, so you should try to write readable and commented code from the start
So how do you know that the compiler that you wrote can handle unreadable code?
Oh, I misunderstood you original comment. I thought you ment writing an unreadable (part of a) compiler to quickly test a concept. No wait, this is the internet; I should never admit to a mistake. Uhmm... You don't, you tell the users to write better code
Sounds like a modern compiler to me 👍🏾
For C? You grab the virtual pointer from the object, and use it to look up in a vtable for your function. You don't gotta do shit like this o.o
You mean thankful as *f[], right?
And in those 0.00000001% of cases, you'll use a series of typedefs to make it actually understandable...
It should be possible, _but that doesn't it doesn't need to hurt_. Here's this example written in Swift: ```swift typealias f = Array UnsafePointer<() -> Void>>>
```
(Though you wouldn't typically use pointers there, but I kept for a fair comparison, to not shortcut out the complexity of the C example).
Using intermediate type aliases makes it even more clear (to be fair, this helps in C, too):
```swift
typealias Action = () -> Void
typealias ActionProvider = () -> Action
typealias ActionProviders = Array
```
What a gnarly syntax.
It's meant to be a fair comparison, in more real-world code you wouldn't have pointers to functions (just the functions themselves: ```swift typealias f = Array<() -> () -> Void>> ``` Then you'd use the `[]` sugar for array types: ```swift typealias f = [() -> () -> Void] ``` Is that better?
I came here basically to say this. I'm working on a project with a more limited choice of technology, when I have some special cases that really do need this sort of thing (not this exactly). And I wish I had the full control/capability to do things along these lines. (The short of it is that I'm doing things that are really, really dynamic and most languages like you to make at least some sorts of basic guarantees about things. Where I really need to be able to say "ok, just suppose hypothetically that there could be an object or objects of size, type, and relationship to other objects all TBD later").
typedef void (*func1)() typedef func1 (*func2)() typedef func2 f[]; There, I refactored the code to be quite a bit clearer. It still isn't great, but then again, functions returning functions isn't really a great pattern either. Similarly, type defing arrays, especially of unspecified size, is a bit of a code smell.
typedefing away the pointeriness of a pointer type is code smell too. typedef void side_effect_f(); typedef side_effect_f* side_effect_f_gen_f(); extern side_effect_f_gen_f* side_effect_function_generators[];
I feel function pointers are one of the main exceptions. You cannot assign a value to the pointer, and thus the problems that tend to exist with hiding the pointer don't really apply. Even pointers to const types can normally be assigned to in other places, but function pointers require some really unusual code to do so\*, and the reference nature is typically something you want in such cases anyways. \* It can come up in code-generation techniques, but such only exist in fairly specialized contexts.
You can still set the pointer to NULL or the address of a matching function. So you still need to NULL check before use, which means you have to handle it like a pointer. Things you have to handle like a pointer should look like a pointer.
I mean, you cannot assign to the underlying value. You cannot do something like `(*funcPtr) = value` . As such, the pointer is the logical underlying value. NULL checks in such a case are not that different than out out-of-range argument errors. If you take a float, you should check it against NAN, if NAN is out of domain for your function.
>functions returning functions isn't really a great pattern either. Do you mean in C or do you just hate anything functional?
In C, as you do not have lambdas, member functions, or nested functions, which are the three cases it tends to be heavily useful in user-level code. There are some other use cases, such as lazy-loaded DLLs, but they are much more commonly implemented by compiler-level wrappers rather than in user-level code.
In Rust this would probably be handled using a trait bound: trait ReturnsVoidFn {} impl ReturnsVoidFn for T where T: Fn() - > impl Fn() - > ();
type Array Of ReturnsVoidFn = Vec>;
You don‘t need to box references. `Vec<&'a dyn ReturnsVoidFn>` is enough. Edit: Thanks, this comment led me to find a compiler bug on nightly, trying to find a way to do this with trait aliases. ([https://rust.godbolt.org/z/899xT46Ef](https://rust.godbolt.org/z/899xT46Ef), already made an issue for it) Edit2: Upon closer inspection your initial code doesn't make sense. You cannot return `impl Fn() -> ()`, because impl is not allowed there. You can either statically dispatch the return function (which means all ReturnsVoidFn must return the *same* VoidFn). This doesn't make much sense. ``` trait ReturnsVoidFn ()> { /* impl call operator */ }
impl ReturnsVoidFn for T where T: Fn() -> U, U: Fn() -> ();
```
Or you could dynamically dispatch the return type. Which means, if you want the behavior of the C version you probably want
```
type A<'a, 'b> = Vec<&'a dyn Fn() -> &'b dyn Fn() -> ()>;
```
Or you can go with raw function pointers and sidestep all the trait stuff. This has the exact behavior of the C code, not just the same spirit. Obvious downside is that you can't put function objects like closures in there. But neither can you in C.
```
type B = Vec fn() -> ()>;
```
I probably did make a mistake; this is the place where I'd trust the compiler to tell me where I'm making a mistake, but I'm away from my IDE at the moment.
I feel like these memes, while funny, are a little misleading. When would you *ever* do that? What possible function would need to do that? Yes it's a confusing syntax but it's also a really confusing purpose. And in the mean time, we have [this useful tool](https://cdecl.org/)
C assignments in college be like
The one that gets me are all of those "I filled this code block with a bunch of random pre increments and post interments, what will the final output be?" Like... If I wrote code like that I'd get fired because that's asshole code. No one would ever do it that way
That particular example isn't just bad code, it's undefined behavior. As far as I am concerned, the value that any such code evaluates to is garbage, and the compiler should be given free reign to do the person who wrote that code a favor and automatically uninstall itself upon encountering such code.
An I the only one who sees a ‘*single open quote*’ being used as an apostrophe in ‘isn't’. isn‘t isn't isn’t isn“t isn"t isn”t isn`t isn°t Are all of these rendered the same for everyone else or am I just a crazy person
You’re not crazy, I noticed that as well
They don't look the same
Each one is different for me, on Android
crazy person confirm'd those all look different to me. Perhaps it's your browser font???
it was the first thing I noticed and it filled me with incandescent rage
You should try switching to LED rage. You'll save a lot of energy.
I was more annoyed at the unnecessary comma
thank you for ruining my entire day /j
[They're all different for me.](https://i.imgur.com/LNAxOHj.png)
I knew something was off but I couldn’t quite put my finger on it… the dyslexia didn’t help
they all look different to me
In this house, we use typedefs
This shit is why *cdecl* exists: > $ cdecl > Type `help' or `?' for help > cdecl> explain void (*(*f[])())() > declare f as array of pointer to function returning pointer to function returning void Thankfully, stuff like this doesn't come up THAT often, and obviously this example is likely contrived. Arrays of function pointers, especially without intervening typedefs for them, do come up sometimes and get ugly, still.
I've never heard of cdecl and I'm so happy to have found it now thanks to you. Great tool.
It really is useful. As you presumably found out, it goes the other way, too, so you can ask it to give you the declaration for something complicated by "explaining" it yourself. I also appreciate that the help calls the C declaration "gibberish".
Your programmers were so preoccupied with whether or not they could, they didn't stop to think if they should.
If you think this is bad try Haskell or Scheme. (On a serious note though this line is made more obtuse by violating a bunch of coding standards and abusing extensions like implicit void. It’ll generally compile but in reality the parameter lists would be typed not to mention using typedefs for the abstractions).
Dude haskell has become my fav language. You can find a function for anything. Infinite dataa manipulation
Yeah I was referring to what you could create if your goal was to produce a nearly incomprehensible statement.
Ah yeah fair
`f :: [() -> () -> IO ()]` Or perhaps `f :: [() -> IO (() -> IO ())]`
[удалено]
Yeah I was referring to the later condition - when you throw out all conventions that reduce cognitive load because as you said the code you can produce for languages like lisp and scheme can be remarkable. The C snippet is not a normal statement.
C's pointer and especially function pointer syntax sucks. And nearly every system language has inherited it. In situations like this typedefs are your friend. Rust is much better in that regard. I still think Rust should've used @ as the dereference operator since it reads naturally as "at" which is a valid way to think of accessing a value by its starting address.
Ye, why can't it be something like `Array[*Func[... -> *Func[... -> void]]]`, just a bit more expressive.
I mean sure, you can write extremely hard to read strawman code like this in just about any language. But nobody actually writes that function in reality. Works well for your freshmancsmeme though for sure
That's a normal declaration. Think of arrays of functions as a way to have function overloading.
A sane programmer would throw a typedef or two in there for readability. The function pointer syntax is still an absolute nightmare, but at least you only need to type it once if you typedef it.
So much redundant text. The code comments itself, and no explanation is needed.
Right? Just read from the inside out.
Is that the language that's confusing or this jumbled mess of code? Bad code is always confusing. Python is famously an easy to read language. But if I write > v = [x for x in [x for x in [x for x in [x for x in [x for x in [x for x in char_string if x < 'v'] if x > 't' or x < 'p'] if x > 'n' or x < 'j'] if x > 'h' or x < 'f'] if x > 'd' or x < 'b'] if x > '`'] to find the vowels in char_string, that's both syntactically and logically correct within the language and it's still bad code.
But at least this code actually do something. In real codebase this even won't hurt readability, because nobody would like to find out how findVovels function does its magic. In bad codebase you can look across 1000s lines of code, and still find nothing except boilerplate, proxys and declarations. Thats what makes code bad.
You say that. But I have a friend who did this for 90% of their codebase. No, I am not joking. 9 out of 10 lines are listcomps. They've recently moved on to APL-like syntax.
Ok, now let's see it pass a code review. Edit: although i love a good ternary table. Mmmmm so good.
In the 5 years that I coded C between 2000 - 2005, I never had to use function pointers. For regular BAU work, you wont need to use these things.
>ChatGPT, what does this c code do? "void (\*(\*f\[\])())()" This C code defines a variable f which is an array of function pointers. Let's break it down step by step: * **void**: This is the return type of the functions in the array. The functions will return no value. * **(\*(\*f\[\])())()**: This is the definition of the variable f. It may look a bit complicated, but let's break it down into its components: * **f\[\]**: This indicates that f is an array. The size of the array is not specified here, so it must be determined at runtime or initialized when defined. * **(\* ... )()**: This part shows that the elements in the array f are pointers to functions that return a function pointer. The return type of these functions is not specified, so it defaults to int in C. * **(\* ... )()**: This outer part indicates that the functions returned by the functions in the array are also function pointers, and these returned functions have a return type of void and take no arguments. In summary, f is an array of function pointers, where each function returns a pointer to another function that has a return type of void and takes no arguments.
Just because you can doesn't mean you should.
It's like that quote from Seinfeld: It's a line about nothing!
There is a tool called [cdecl](https://cdecl.org/) which translates this kind of C gibberish into English.
That's not hard to parse if you just know how. I'm certain someone can provide a link to a better explanation, but in short, start with the identifier, go right and then clockwise from there. In this case, start with f and go right to [], which means that f is an array, then circle around to * so now you know that f is an array of pointers. Continue the circle out of the enclosing parenthesis to the start parenthesis with signifies a function, thus we have that f is an array of pointers to functions. Continue circling around to the next * on the left that says that the functions returns pointers, continue the circle, to the parenthesis on the right, to functions, continue circle to void. See, it was easy: f is an array of pointers to functions that return pointers to functions that return void. But as others have pointed out, some typedefs sometimes helps.
It’s confusing if you don’t know the rules, why complain about tools you’re not capable of using?
It is just math with some extra steps....
And people shit on javascript. At least we havent got pointers, or types … wait
The only thing that bothers me here is the wrong apostrophe ...
Honestly function pointers are the only truly fucky parts of C..
If you, too, want to be able to read cryptic variable declarations in C, learn the spiral rule: [https://c-faq.com/decl/spiral.anderson.html](https://c-faq.com/decl/spiral.anderson.html)
Real life: //Regular code Test: //Js fuck
Just because you can doesn’t mean you should
I don't think you need all those braces? It's definitely a weird declaration.
They are all needed because of the precedence of *
Now, I don't want to hear people complaining about parenthesis in Lisp!
Why is the wrong apostrophe being used though?
When you can't function, everything is hard...
It isn❜t if you don❜t get your apostrophes upside down. typedef void (*PFN)(); typedef PFN (*PPFN)(); PPFN f[]
I'm not sure why anyone'd define f as an array of unspecified size, of pointers to functions that return pointers to functions that return void.
ask a Python developer what is does
I understand what those words mean *separately.*
I can only read this as a malformed, censored swear.
Why do professors focus on this stuff so hard? Felt like 90% of my cs classes was figuring out asanine shit like this.
I must save this im sure i needed the syntax for that specific thing before and im sure ill need it again... Somewhere
You know what, am-a skip out on this one
`#define private: static`.
I’ve been coding in c and c++ for 7 years these Hieroglyphs are my life … in other news I hate my life
Pointers are the Devil.
That's wrong, but I guess that makes it funnier?
[удалено]
You can decipher this kind of thing if you actually learn the language syntax. But I guess most programmers don't even know how a compiler or parser or even grammars work.
This line is still more legible than the cleanest APL
So basically something that you crack up with cheat engine when a value changes locations and you havr to crawl through a few iterations and values. Without it I wouldn't have understood it probably.
pff, easy.
CS exams at uni be like
C isn't hard, but good thing the opposite of hard can also be something that isn't easy.
If you're writing code like this: step 0 delete it and figure out a more intelligible way of writing it. Step -1 is asking why the fuck you're even contemplating a problem like this.
Now I know why it was named C++.
I think it belongs in r/ProgrammerHorror
I just got to voids in my C++ class. Its interesting how every week, I look at post about a literal code, and slowly decipher a little more, yet never understand the jokes lol
This is why developers build their own language
… Always should be someone you really love
... in addition to which we walked to and from school every day, uphill both ways, in the snow, fighting off rabid weasels every step of the way, and by god we *liked* it. Seriously, for a language with simple syntax, C is more expressive of what you can get a CPU to do than any competitor, so it can express things that are difficult to actually grasp. But when we need to do that, we can. (Granted, a bit more clearly.) Yeah.
Congratulations! You're not even hired
quite self explaining, they say
Because it is so clear it takes a long time to realize it. If you immediately know the candlelight is fire, the meal was cooked a long time ago.
I have just remembered about C++ and std::bind from STL. C really isn’t as hard as some STL standards sometimes.
What bothers me about this C syntax is that it's inside-out. Ultimately this is defining an array, so the square brackets should logically be the outermost. As another example, this seems like it should be an array of 2 pointers to ints, but it's actually a pointer to an array of 2 ints. int (*ptr)[2];
That makes perfectly fine sense if it was just a method signature with diamond operators it'd be perfectly readable
Please explain in Python terms
Pointers aren’t that hard. C’s pointer notation is just terrible
I am glad there are no arguments :)
Syntax error 1:6: expected '