Programming Confessions Thread
-
@Tsaukpaetra said in Programming Confessions Thread:
I'm not sure I see the point....
void const *as_const_void(void const *p){ return p; } //... void *src = ...; void *dst = ...; memcpy(src, dst, n); //incorrect but no error memcpy(as_const_void(src), dst, n); //incorrect & error memcpy(dst, as_const_void(src), n); //correct & no error
Though really it's better to just always declare the
src
variable asvoid const *
in the first place, which accomplishes the same effect. I was assuming though that you were using a mutable array as thesrc
though and thus you'd need an extra variable, makingas_const_void
more appealing.
-
@LB_ said in Programming Confessions Thread:
Though really it's better to just always declare the
src
variable asvoid const *
in the first place, which accomplishes the same effect. I was assuming though that you were using a mutable array as thesrc
though and thus you'd need an extra variable, makingas_const_void
more appealing.That's my confusion. I don't know what
as_const_void
would do for me, becauseyou were using a mutable array as the
src
though and thus you'd need an extra variablethis.
-
@Tsaukpaetra said in Programming Confessions Thread:
@LB_ said in Programming Confessions Thread:
Though really it's better to just always declare the
src
variable asvoid const *
in the first place, which accomplishes the same effect. I was assuming though that you were using a mutable array as thesrc
though and thus you'd need an extra variable, makingas_const_void
more appealing.That's my confusion. I don't know what
as_const_void
would do for me, becauseyou were using a mutable array as the
src
though and thus you'd need an extra variablethis.
as_const_void
negates the need for an extra variable.void setup_other_arr(int dst_array[5], _Bool special) { int src_array[5] = {1, 2, 3, 4, 5}; if(special) { src_array[2] = -3; } memcpy(as_const_void(src_array), dst_array, sizeof(src_array)); //catches your mistake }
-
@LB_ said in Programming Confessions Thread:
catches your mistake
But it's a mistake made exactly once? I don't get it.
I don't feel the need to create a whole function that functionally does nothing now that the correct code has been made.
-
@Tsaukpaetra A lot of things in programming are entirely unnecessary once the correct code as been made. Their usefulness comes from catching the times when you accidentally don't make the right code on the first try. Casting things to
const
has saved me many times.EDIT: And, sometimes what is "correct" changes over time. The usefulness of things like
as_const
can resurface as code needs to be changed. Maybe not in your case with this specificmemcpy
, but in general for sure.
-
@LB_ said in Programming Confessions Thread:
in general for sure.
In general I've never used
const
unless the compiler whined at me. Maybe this is a bad habit?
-
@Tsaukpaetra Yes, I'd consider it to be a bad habit if you never use
const
except when you get compile errors from not using it. Aside from improving code quality, readability, and catching mistakes, in some cases usingconst
can even enable compiler optimizations that wouldn't otherwise be possible. In C you also haverestrict
too, though I am less sure how to use it.
-
@LB_ I have, at some point, looked into this (as well as enabling
-Wwrite-strings
which makes string literals const). However I am cursed with an existing codebase which does not merely not use const, it also likes on occasion writing to its supposed input arguments, usually to revert the change a few lines later.
-
@PleegWat Ah, yeah, that's something I have noticed as a problem especially with the mistake that is null-terminated strings. Often I see code that write a null to a "const" string in order to pass it as a substring to another function without making a copy, then it restores the original byte it had overwritten. This is why we have length-terminated strings and
string_view
in C++ now. It's possible to do the same in C and some libraries do, but any library that doesn't makes the whole chain need an extra null...
-
@Tsaukpaetra said in Programming Confessions Thread:
@LB_ said in Programming Confessions Thread:
in general for sure.
In general I've never used
const
unless the compiler whined at me. Maybe this is a bad habit?I consider const correctness absolutely mandatory for clean code.
-
@topspin said in Programming Confessions Thread:
@Tsaukpaetra said in Programming Confessions Thread:
@LB_ said in Programming Confessions Thread:
in general for sure.
In general I've never used
const
unless the compiler whined at me. Maybe this is a bad habit?I consider const correctness absolutely mandatory for clean code.
I'm still not understanding what makes an extra word cause code to be "cleaner", but perhaps I should find a book on the matter, since nobody yet has given any substantial rationality, and this is the wrong thread.
Perhaps I should spend some $currency to create a thread....
-
@Tsaukpaetra said in Programming Confessions Thread:
@topspin said in Programming Confessions Thread:
@Tsaukpaetra said in Programming Confessions Thread:
@LB_ said in Programming Confessions Thread:
in general for sure.
In general I've never used
const
unless the compiler whined at me. Maybe this is a bad habit?I consider const correctness absolutely mandatory for clean code.
I'm still not understanding what makes an extra word cause code to be "cleaner", but perhaps I should find a book on the matter, since nobody yet has given any substantial rationality, and this is the wrong thread.
Perhaps I should spend some $currency to create a thread....
If I hand you a const reference to an object, I know you can’t modify it (fuckery with casts notwithstanding). On the flip side, if I have a const object and want to hand it to you, but you take a non-const reference even though you purport not to modify it, then I can’t do it because your API isn’t correct.
-
@Tsaukpaetra said in Programming Confessions Thread:
I'm still not understanding what makes an extra word cause code to be "cleaner", but perhaps I should find a book on the matter, since nobody yet has given any substantial rationality, and this is the wrong thread.
I found this FAQ helped clear up a few things for me:
-
@Watson I got to this part and started throwing up uncontrollably:
-
@hungrier I know, west const is repulsive and unappealing to me too, but it's a fairly popular style and I think we shouldn't shame it just for being different.
-
@LB_ From what I can see, East const makes the most sense, especially with the guide's repeated mantra of "read from right to left". In fact when I got to that section I started wondering why it didn't just start with East const in the first place.
But anyway my post was more about the combination of double pointers and consts, not either of the const styles
-
@LB_ said in Programming Confessions Thread:
@hungrier I know, west const is repulsive and unappealing to me too, but it's a fairly popular style and I think we shouldn't shame it just for being different.
"East const" might be more consistent, but only if you are OCD enough to declare garbage like the
X const* const* const baz
example. Why would you ever write a type like this?! For 98% of normal people and use cases, you only need one const. In that case there's no point arguing ifX const
orconst X
is more consistent, as that's a moot question, and I happen to think thatconst X
reads more naturally.
The latter might of course be personal bias.
-
@Watson said in Programming Confessions Thread:
@Tsaukpaetra said in Programming Confessions Thread:
I'm still not understanding what makes an extra word cause code to be "cleaner", but perhaps I should find a book on the matter, since nobody yet has given any substantial rationality, and this is the wrong thread.
I found this FAQ helped clear up a few things for me:
Another point not mentioned there (this is convention, not language rule): If your methods are
const
, I expect them to be thread-safe.
-
@topspin said in Programming Confessions Thread:
"East const" might be more consistent, but only if you are OCD enough to declare garbage like the
X const* const* const baz
example.It all depends on what is constant. The easternmost
const
in it is a bit low utility except when put on a non-local variable (global or file scope) as it just says that the particular pointer in it can't be changed. (It's the sort of thing that's useful for me when pointing to memory mapped hardware; the address of it really can't be changed by the program in any useful way. Most of the time for local variables it's a meh, and some compilers don't put it in the checked function signature for arguments; MSVC does though.) The other two are more generally useful, as they can describe a constant array (middle) of pointers to constant things (western); you can conceive of reasons why such an array might need to be non-modifiable (because something else is managing it) and you can obviously think of why an end structure might need the no-change-me guarantee.Having the ability to control this stuff is useful.
-
@dkf I’d still probably just go with
const X**
or, preferably, some array class. But I guess C people don’t mind stuff likedouble****
.
-
@topspin You can do fancy stuff like that in C++, but you're more restricted in C. You can
typedef
things, of course, but putting pointers inside those tends to lead to more confusion in the longer run.
-
@topspin said in Programming Confessions Thread:
@LB_ said in Programming Confessions Thread:
@hungrier I know, west const is repulsive and unappealing to me too, but it's a fairly popular style and I think we shouldn't shame it just for being different.
"East const" might be more consistent, but only if you are OCD enough to declare garbage like the
X const* const* const baz
example. Why would you ever write a type like this?! For 98% of normal people and use cases, you only need one const. In that case there's no point arguing ifX const
orconst X
is more consistent, as that's a moot question, and I happen to think thatconst X
reads more naturally.
The latter might of course be personal bias.There is no west const for function signature types. East const is therefore more consistent by default.
using t = int; using tc = int const; using f = int(); using fc = int() const;
Note:
fc
can't be used for non-member functions.
-
@topspin said in Programming Confessions Thread:
If your methods are const, I expect them to be thread-safe.
That assumption sounds dangerous. A function can be thread-safe, reentrant, and/or signal-handler-safe. These are related, but different concepts. Those three properties span up 8 different categories, and I'm quite sure you can write code that goes in at least half of them by accident. The only combination I'm not sure can easily be hit is signal handler safe but not reentrant.
I don't think a function can be const. Most likely you mean a function which only takes const arguments, but that's not a valuable limitation. A pure function (which only acts on its arguments, does not dereference its arguments, does not reference global variables, and only calls other pure functions) will be thread-safe, reentrant, and signal-handler safe. There are a couple of related concepts.
-
@PleegWat said in Programming Confessions Thread:
@topspin said in Programming Confessions Thread:
If your methods are const, I expect them to be thread-safe.
That assumption sounds dangerous. A function can be thread-safe, reentrant, and/or signal-handler-safe. These are related, but different concepts. Those three properties span up 8 different categories, and I'm quite sure you can write code that goes in at least half of them by accident. The only combination I'm not sure can easily be hit is signal handler safe but not reentrant.
I don't think a function can be const. Most likely you mean a function which only takes const arguments, but that's not a valuable limitation. A pure function (which only acts on its arguments, does not dereference its arguments, does not reference global variables, and only calls other pure functions) will be thread-safe, reentrant, and signal-handler safe. There are a couple of related concepts.
C++, 20 years ago at least, has const member functions. If I remember right, guaranteed by the compiler to not change the object's state. It's a feature I've missed in C#, Java, Scala, and others.
-
@PleegWat said in Programming Confessions Thread:
@topspin said in Programming Confessions Thread:
If your methods are const, I expect them to be thread-safe.
That assumption sounds dangerous. A function can be thread-safe, reentrant, and/or signal-handler-safe. These are related, but different concepts. Those three properties span up 8 different categories, and I'm quite sure you can write code that goes in at least half of them by accident. The only combination I'm not sure can easily be hit is signal handler safe but not reentrant.
I don't think a function can be const. Most likely you mean a function which only takes const arguments, but that's not a valuable limitation. A pure function (which only acts on its arguments, does not dereference its arguments, does not reference global variables, and only calls other pure functions) will be thread-safe, reentrant, and signal-handler safe. There are a couple of related concepts.
Where did I say a "const function"? I said a const method!
That might have been a bit of a simplification, but in absence of modifying global state, out-variables, and having callbacks, it's a good enough rule. To make it a bit more precise, I expect a const method to be free of data races on the object. Since, conceptually, a const method does not modify anything but only reads it, and multiple concurrent reads do not form a data race. That means if your method is only conceptually declared const but internally has something like a mutable cache, e.g. for expensive computations, the method should internally synchronize that cache. Or, if that's not desired, not be declared const. Of course you're right that if it doesn't modify the object itself, but either out parameters or global state it isn't thread safe.
-
@topspin said in Programming Confessions Thread:
Where did I say a "const function"? I said a const method!
INB4 "Aren't those the same things?"
This conversation has soared straight over my un-groomed head....
-
@Tsaukpaetra said in Programming Confessions Thread:
INB4 "Aren't those the same things?"
<> In some languages, yes. In C++, no (since the method is bound to an instance). </>
-
@blakeyrat Reshaper has pretty much killed visual studio.
-
This post is deleted!
-
I think I did this right, but I have no way to test until I get the other half that actually provides the data.
bool Load(Stream* data){ //First fetch the Magic int magicCheck = 0; if(sizeof(int) != data->readBytes((char*)&magicCheck,sizeof(int))){ //We didn't have enough bytes to make an int... return false; } if(magicCheck != configLayoutMagic) return false; //Got this far, try to read the data into ourselves data->setTimeout(10000);//Ten seconds should be enough time to read a kilobyte or so... if(ConfigSize() != data->readBytes((char*)this,ConfigSize())){ return false; } //You made it! We should now be full of the new config data... return true; }
This is reasonable, right?
-
Casting
this
tochar*
looks really questionable to me. Writing data to thethis
pointer, even more so.
-
@error said in Programming Confessions Thread:
Casting
this
tochar*
looks really questionable to me. Writing data to thethis
pointer, even more so.Dubious, but I hope it's a POD class. At least
ConfigSize()
should besizeof(Foo)
.
-
@topspin said in Programming Confessions Thread:
I hope it's a POD class
Yes. Any pointers to other things in there and life gets “very exciting” to debug. This feels like the sort of method that ought to only ever be invoked from a constructor, and a failure to fill things out should result in an exception so that the damaged class doesn't get loose into the rest of the program.
-
@error said in Programming Confessions Thread:
Casting
this
tochar*
looks really questionable to me. Writing data to thethis
pointer, even more so.Yeah. I know this can work in C/C++, if it's a struct where the first field is at the start of the memory. But even then, surely you want a char* field actually declared and read into that?
-
Guys, this is @Tsaukpaetra we're talking about. How would he achieve his nine-five uptime without writing buggy code (and running it on a dodgy hardware)?
-
@bobjanova said in Programming Confessions Thread:
@error said in Programming Confessions Thread:
Casting
this
tochar*
looks really questionable to me. Writing data to thethis
pointer, even more so.Yeah. I know this can work in C/C++, if it's a struct where the first field is at the start of the memory. But even then, surely you want a char* field actually declared and read into that?
Treating the entire struct as binary data isn't that unreasonable to me, but indeed it should be POD and not contain any pointers. And in that case you would cast a pointer to the struct to char* when passing it to functions which handle unstructured data. void* is also an option, but it depends on the libraries you're using.
I've done similar things in C for large-volume data (memory map a file, cast the resulting pointer to array of struct). I've got some ancient code which does the same for configuration files, but it's a complication if you ever need to upgrade it and I prefer just using a text-based or other defined serialized format and dealing with the parsing code.
-
@topspin said in Programming Confessions Thread:
@error said in Programming Confessions Thread:
Casting
this
tochar*
looks really questionable to me. Writing data to thethis
pointer, even more so.Dubious, but I hope it's a POD class. At least
ConfigSize()
should besizeof(Foo)
.It is. Even the strings are staticly-sized Char arrays, there (shouldn't be) any other pointers at all. Which reminds me I should double-check the functions that use mentioned strings to ensure they intentionally zero-terminate them after taken from the struct...
@dkf said in Programming Confessions Thread:
@topspin said in Programming Confessions Thread:
I hope it's a POD class
Yes. Any pointers to other things in there and life gets “very exciting” to debug. This feels like the sort of method that ought to only ever be invoked from a constructor, and a failure to fill things out should result in an exception so that the damaged class doesn't get loose into the rest of the program.
It started as an overloaded constructor, but I have no idea how to do exceptions in Arduino, so next-best-thingd it.
@PleegWat said in Programming Confessions Thread:
but it's a complication if you ever need to upgrade it and I prefer just using a text-based or other defined serialized format and dealing with the parsing code.
I really wanted to make the configuration object fillable from json, but c++ and Arduino would make the resultant code way too hefty.
As is, I'm pondering the big-boy computer generation I'm going to be writing next (the other side of this equation) which will more than likely use a more sane format and build the data from that.
Just need to make sure the structured data gets laid out the same way...
-
@Tsaukpaetra said in Programming Confessions Thread:
Arduino
Forgot you're on an Arduino project. Yeah, in that case I can imagine doing the 'real' config parsing on a PC tool which is version-locked to the Arduino app.
-
@PleegWat said in Programming Confessions Thread:
Forgot you're on an Arduino project
Yeah, my next post here will probably about how I tried to take a sketch description of "inversion of control" and kinda-sorts attention attempted to do that in Arduino, but not really, but okay fine let's-- whatever let's do inheritance-kinda!
-
@PleegWat said in Programming Confessions Thread:
I can imagine doing the 'real' config parsing on a PC tool which is version-locked to the Arduino app.
We do that sort of thing a lot with our C code that we deploy in similar circumstances, except we also push pointers over because we can control the memory layout prior to the app starting and can also poke around after the app finishes. (Yes, we have remote access to
malloc()
andfree()
in the runtime.) It's made for a weird coding style where there's almost none of the usual code you find for application startup and shutdown. Which is good because we've never attached a real filesystem to the target hardware…
-
@Tsaukpaetra said in Programming Confessions Thread:
@PleegWat said in Programming Confessions Thread:
Forgot you're on an Arduino project
Yeah, my next post here will probably about how I tried to take a sketch description of "inversion of control" and kinda-sorts attention attempted to do that in Arduino, but not really, but okay fine let's-- whatever let's do inheritance-kinda!
So
glib
?
-
@mikehurley said in Programming Confessions Thread:
@Tsaukpaetra said in Programming Confessions Thread:
@PleegWat said in Programming Confessions Thread:
Forgot you're on an Arduino project
Yeah, my next post here will probably about how I tried to take a sketch description of "inversion of control" and kinda-sorts attention attempted to do that in Arduino, but not really, but okay fine let's-- whatever let's do inheritance-kinda!
So
glib
?Is that a suggestion or warning?
-
@Tsaukpaetra said in Programming Confessions Thread:
@mikehurley said in Programming Confessions Thread:
@Tsaukpaetra said in Programming Confessions Thread:
@PleegWat said in Programming Confessions Thread:
Forgot you're on an Arduino project
Yeah, my next post here will probably about how I tried to take a sketch description of "inversion of control" and kinda-sorts attention attempted to do that in Arduino, but not really, but okay fine let's-- whatever let's do inheritance-kinda!
So
glib
?Is that a suggestion or warning?
It has a reputation for being OO in C.
-
@mikehurley said in Programming Confessions Thread:
It has a reputation for being OO in C.
As opposed to libXt, which definitely was OO in C (and utterly horrible)?
-
Just wasted about a half hour fiddling with Hibernate
@OneToOne
annotations before I realized that I forgot to annotate the other class as an@Entity
with a@Table
.
-
@boomzilla ORM: not even once.
-
@Gąska lame.
-
@Gąska
Oh come on. Next to meetings, EntityFramework is the second best way to turn your work day into the evening without getting anything useful done. And EntityFramework doesn't require you pay for donuts
-
@izzion said in Programming Confessions Thread:
And EntityFramework doesn't require you pay for donuts
Go to better meetings where other people pay.
-