Coding: Fleeting Thoughts

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

User avatar
ucim
Posts: 6888
Joined: Fri Sep 28, 2012 3:23 pm UTC
Location: The One True Thread

Re: Coding: Fleeting Thoughts

Postby ucim » Tue Apr 05, 2016 8:31 pm UTC

You, sir, name? wrote:At any rate, the language seems to be evolving away from the syntax that bothers you with the introduction of features like uniform initialization.
I first read that as "...features like unicorn initialization". That would be so much cooler - might even make it worth coding in C++. :)

Jose
Order of the Sillies, Honoris Causam - bestowed by charlie_grumbles on NP 859 * OTTscar winner: Wordsmith - bestowed by yappobiscuts and the OTT on NP 1832 * Ecclesiastical Calendar of the Order of the Holy Contradiction * Heartfelt thanks from addams and from me - you really made a difference.

User avatar
You, sir, name?
Posts: 6983
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City
Contact:

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Tue Apr 05, 2016 9:10 pm UTC

ucim wrote:
You, sir, name? wrote:At any rate, the language seems to be evolving away from the syntax that bothers you with the introduction of features like uniform initialization.
I first read that as "...features like unicorn initialization". That would be so much cooler - might even make it worth coding in C++. :)

Jose


I guess unicorn initialization is when an unitialized variable accidentally has a sane value and your program only works when other people aren't around to see it.
I edit my posts a lot and sometimes the words wrong order words appear in sentences get messed up.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Wed Apr 06, 2016 12:51 pm UTC

Code: Select all

template<class T>
struct unicorn {
  std::aligned_storage_t<sizeof(T),alignof(T)> data;
  bool init = false;
  T& get() { return *reinterpret_cast<T*>(&data); }
  T const& get() const { return *reinterpret_cast<T*>(&data); }
  operator T&()&{ return get(); }
  operator T const&()const&{ return get(); }
  operator T&&()&&{ return std::move(get()); }
  operator T const&&() const&&{ return std::move(get()); }
 
  ~unicorn() { if (init) get().~T(); }
 
  template<class U>
  void operator->*(U&& u){
    ::new( (void*)&data ) T(std::forward<U>(u));
    init = true;
  }
};

int main() {
  unicorn<int> x;
  x->*3;
}
Last edited by Yakk on Thu Apr 07, 2016 2:04 pm UTC, edited 2 times in total.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
You, sir, name?
Posts: 6983
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City
Contact:

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Wed Apr 06, 2016 1:15 pm UTC

Poetry --^
I edit my posts a lot and sometimes the words wrong order words appear in sentences get messed up.

User avatar
Link
Posts: 1419
Joined: Sat Mar 07, 2009 11:33 am UTC
Location: ᘝᓄᘈᖉᐣ
Contact:

Re: Coding: Fleeting Thoughts

Postby Link » Thu Apr 07, 2016 12:52 pm UTC

CFT: something wasn't working as I expected. Turns out that instead of if i < 2, I'd written if 1 < 2. Image

User avatar
e^iπ+1=0
Much, much better than Gooder
Posts: 2065
Joined: Sun Feb 15, 2009 9:41 am UTC
Location: Lancaster

Re: Coding: Fleeting Thoughts

Postby e^iπ+1=0 » Sun Apr 10, 2016 3:18 pm UTC

I have a function that I want to return multiple values. In this case it's three floats. What's the general best practice way to do this in C++ with no C++ 11 (so no tuples)? Structs, pointers to arrays, nested pairs, something else?
poxic wrote:You, sir, have heroic hair.
poxic wrote:I note that the hair is not slowing down. It appears to have progressed from heroic to rocking.

(Avatar by Sungura)

User avatar
Flumble
Yes Man
Posts: 2262
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Sun Apr 10, 2016 4:15 pm UTC

Unless your floats are specifically a 3-vector (in which case an array is most suitable... unless the rest of the code already has a structure for vectors), I'd advise a struct.
If the (float,float,float) tuple needs to be reused for very different kinds values, you can always call it something like TupFFF with fields f1, f2, f3. Otherwise, you can give them sensible names.


RE: combining chat protocols
Thanks for the replies everyone.
I've decided to go for the XMPP-approach: translate XMPP messages from and to protocol X, transfer them to a local XMPP server (donned with a couple of protocol extensions if possible, like message archiving) and then use a suitable front-end client to actually communicate. This ought to transform the problem of message-passing (especially pushing/polling design) to one of understanding the XMPP library for the language(s) in question and configuring the server.

Argh, why doesn't XMPP just have a monopoly on chatting so there's a decent offering of beginner's guides and less hassle merging chat service providers? :(

[edit]
Also yowsup finally seems to be compatible with the new encryption in whatsapp, so I can use all my procrastination time to work on the above next week. :)

User avatar
You, sir, name?
Posts: 6983
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City
Contact:

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Sun Apr 10, 2016 7:39 pm UTC

e^iπ+1=0 wrote:I have a function that I want to return multiple values. In this case it's three floats. What's the general best practice way to do this in C++ with no C++ 11 (so no tuples)? Structs, pointers to arrays, nested pairs, something else?


std::array<float, 3> is also an alternative if the semantics are sufficient (it's got operator[] and iterators, which is enough for most usecases). std::array is nice since it's all on the stack-bound unless you explicitly allocate the structure on the heap. Needless to say, it's no more or less expensive to copy a std::array<float, 3> than to copy three floats.

--edit--

Huh. This is the 8888:th post in the thread.
I edit my posts a lot and sometimes the words wrong order words appear in sentences get messed up.

User avatar
e^iπ+1=0
Much, much better than Gooder
Posts: 2065
Joined: Sun Feb 15, 2009 9:41 am UTC
Location: Lancaster

Re: Coding: Fleeting Thoughts

Postby e^iπ+1=0 » Sun Apr 10, 2016 8:44 pm UTC

Flumble wrote:Unless your floats are specifically a 3-vector (in which case an array is most suitable... unless the rest of the code already has a structure for vectors), I'd advise a struct.
If the (float,float,float) tuple needs to be reused for very different kinds values, you can always call it something like TupFFF with fields f1, f2, f3. Otherwise, you can give them sensible names.

It's not a 3-vector, it's not being reused, and all the values are very similar kinds of values. Honestly, the code could probably be refactored so that it only returns one value and is then called three times with slightly different input. But given that there's never a time where you'd ever use this code and not call it all three of these times, it seems more sensible to just return the three values some way.

In any case, any particular reasoning for struct? I mean, I guess it makes sense in the general case, which is what I initially asked about. In my particular case, I basically just have a relatively small script, and this thing's the only place I'd use the struct in it. So it seems like it'd be more readable and such to just use an array?

You, sir, name? wrote:std::array<float, 3> is also an alternative if the semantics are sufficient (it's got operator[] and iterators, which is enough for most usecases). std::array is nice since it's all on the stack-bound unless you explicitly allocate the structure on the heap. Needless to say, it's no more or less expensive to copy a std::array<float, 3> than to copy three floats.

Neat. Unfortunately, it looks like std::array is a C++ 11 thing.
poxic wrote:You, sir, have heroic hair.
poxic wrote:I note that the hair is not slowing down. It appears to have progressed from heroic to rocking.

(Avatar by Sungura)

User avatar
You, sir, name?
Posts: 6983
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City
Contact:

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Sun Apr 10, 2016 8:51 pm UTC

Damn. Upon some research, it turns out std::array is virtually identical to boost::array, so if you have access to boost that's a way to go I guess.
I edit my posts a lot and sometimes the words wrong order words appear in sentences get messed up.

User avatar
Flumble
Yes Man
Posts: 2262
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Sun Apr 10, 2016 10:03 pm UTC

e^iπ+1=0 wrote:In any case, any particular reasoning for struct? I mean, I guess it makes sense in the general case, which is what I initially asked about. In my particular case, I basically just have a relatively small script, and this thing's the only place I'd use the struct in it. So it seems like it'd be more readable and such to just use an array?

Apart from being able to tag the floats with sensible names, you have the opportunity to pass it by value instead of returning a pointer and therefore it doesn't need manual memory management (and it can sit on the stack instead of the heap (in case that makes any difference)). Also the compiler can check for valid fields but it can't (easily) check for valid array indices.

User avatar
Xenomortis
Not actually a special flower.
Posts: 1455
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Sun Apr 10, 2016 10:14 pm UTC

Honestly, I think I'd just have three out parameters.
It sucks a little bit because the caller has to set up the pointers and isn't very C++'y, but at least it's obvious.
Image

User avatar
e^iπ+1=0
Much, much better than Gooder
Posts: 2065
Joined: Sun Feb 15, 2009 9:41 am UTC
Location: Lancaster

Re: Coding: Fleeting Thoughts

Postby e^iπ+1=0 » Sun Apr 10, 2016 10:31 pm UTC

You, sir, name? wrote:Damn. Upon some research, it turns out std::array is virtually identical to boost::array, so if you have access to boost that's a way to go I guess.

It appears I technically have access to it, but it'd require a bunch of additional nonsense to make work because of the framework I'm working in (see below).

Flumble wrote:
e^iπ+1=0 wrote:In any case, any particular reasoning for struct? I mean, I guess it makes sense in the general case, which is what I initially asked about. In my particular case, I basically just have a relatively small script, and this thing's the only place I'd use the struct in it. So it seems like it'd be more readable and such to just use an array?

Apart from being able to tag the floats with sensible names, you have the opportunity to pass it by value instead of returning a pointer and therefore it doesn't need manual memory management (and it can sit on the stack instead of the heap (in case that makes any difference)). Also the compiler can check for valid fields but it can't (easily) check for valid array indices.

So, I don't actually know a ton about C++ specifically. The vast majority of the stuff I need to code in it is pretty damn simple (some loops, some basic arithmetic), so I've been able to lean on general coding knowledge quite a bit. As such, I don't understand a ton about memory management and the stack vs the heap and such, and have little idea what you're saying.

Additionally, I'm working in the root framework, which means the code is interpreted rather than compiled the vast majority of the time (I have yet to run any compiled code after working in root for several months).
poxic wrote:You, sir, have heroic hair.
poxic wrote:I note that the hair is not slowing down. It appears to have progressed from heroic to rocking.

(Avatar by Sungura)

User avatar
3fj
Posts: 1715
Joined: Wed Jun 11, 2008 1:13 pm UTC
Location: Land of Whisky and Bagpipes (LOWAB)
Contact:

Re: Coding: Fleeting Thoughts

Postby 3fj » Mon Apr 11, 2016 7:22 am UTC

e^iπ+1=0 wrote:
Flumble wrote:
e^iπ+1=0 wrote:In any case, any particular reasoning for struct? I mean, I guess it makes sense in the general case, which is what I initially asked about. In my particular case, I basically just have a relatively small script, and this thing's the only place I'd use the struct in it. So it seems like it'd be more readable and such to just use an array?

Apart from being able to tag the floats with sensible names, you have the opportunity to pass it by value instead of returning a pointer and therefore it doesn't need manual memory management (and it can sit on the stack instead of the heap (in case that makes any difference)). Also the compiler can check for valid fields but it can't (easily) check for valid array indices.

So, I don't actually know a ton about C++ specifically. The vast majority of the stuff I need to code in it is pretty damn simple (some loops, some basic arithmetic), so I've been able to lean on general coding knowledge quite a bit. As such, I don't understand a ton about memory management and the stack vs the heap and such, and have little idea what you're saying


I think this boils down to what constitutes "good enough" for your solution. The reason you'd use a struct is so that you can decide to change it later on without impacting the code. A new struct for a single method that you'll only ever call a handful of times probably doesn't warrant a struct.
To me, three out variables is the better solution because you're not giving implicit semantic meaning to the order of the array (even if it's a vector or something where the ordering is unsurprising) as opposed to named parameters, but if the script is that small in the first place it really doesn't matter.
Everything's dead until it's alive. Man will exist, and then he will die. Just take the ride!

User avatar
Flumble
Yes Man
Posts: 2262
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Mon Apr 11, 2016 11:49 am UTC

e^iπ+1=0 wrote:
Flumble wrote:Apart from being able to tag the floats with sensible names, you have the opportunity to pass it by value instead of returning a pointer and therefore it doesn't need manual memory management (and it can sit on the stack instead of the heap (in case that makes any difference)). Also the compiler can check for valid fields but it can't (easily) check for valid array indices.

So, I don't actually know a ton about C++ specifically. The vast majority of the stuff I need to code in it is pretty damn simple (some loops, some basic arithmetic), so I've been able to lean on general coding knowledge quite a bit. As such, I don't understand a ton about memory management and the stack vs the heap and such, and have little idea what you're saying.

How would you go about returning an array of floats? You'd need to allocate the memory for the array with new, pass a pointer around and remember to free up the memory with delete in the calling function, right?
Now consider putting your floats in a struct (either as multiple fields or a fixed-size array) or other class, like a vector. You only need to declare an instance of your structure to make it exist and it will be removed for you after it can't be accessed anymore (i.e. gets out of scope).

Also vectors are of course a nice alternative to both arrays and structs when it comes to passing multiple values of the same type. They provide exception handling when accidentally getting a value out-of-bounds, are automatically freed and don't require you to name your fields. (however they define an ordering on your fields, you can't fully initialize them in a single statement (which may or may not increase verbosity in your case) and they're restricted to a single type (which does not apply to your case))

For some reason I've made an example with different (non-pointer) approaches to find out how much verbosity you can avoid:
Spoiler:

Code: Select all

#include <iostream>
#include <vector>

using namespace std;

struct Float3 {
   float f[3];
};

struct Floats {
   float x, y, z;
};

union FloatU {
   float f[3];
};

Float3 someFunc(float x) {
   //Just declare the struct without naming it
   //Double braces since we're initializing the values within the array within the struct
   //NOTE: This notation is a compound literal and is not available in ISO C++ ( http://stackoverflow.com/questions/5515784/is-this-invalid-c )
   return (Float3) {{ 2, 2*x, x }};
}

Floats otherFunc(float x) {
   //Also note that without the struct name, i.e.
   //  return { 42, 2*x, x };
   //GCC will *warn* that it's an initializer list and that it's only available from C++0x
   //However it will compile successfully anyway.
   return (Floats) { 42, 2*x, x };
}

FloatU unionFunc(float x) {
   return (FloatU) {{ 69, 2*x, x }};
}

vector<float> vFunc(float x) {
   vector<float> result(3);
   result[0] = 29;
   result[1] = 2*x;
   result[2] = x;
   return result;
}

int main() {
   //Copy-constructing a fixed-size array is not possible AFAICT, so reference it instead
   
   //Bollocks, a reference to the array can only be stored in a *constant* array when you don't explicitly keep the struct
   //Also the type gets obnoxious, so let's throw in a typedef
   //NOTE: this is caught in GCC<=4.1.2 as invalid reference to a temporary object; uncaught in GCC>=4.5.2
   typedef const float CArr3[3];
   CArr3 &constResult = someFunc(8).f;
   cout << constResult[0] << ", " << constResult[1] << ", " << constResult[2] << endl;
   
   //If keeping the struct, it's suddenly possible to reference the array
   Float3 r = someFunc(7);
   float (&result)[3] = r.f;
   result[1] = 3;
   cout << result[0] << ", " << result[1] << ", " << result[2] << endl;
   
   //It is of course possible to *not* extract the array
   Float3 float3 = someFunc(5);
   cout << float3.f[0] << ", " << float3.f[1] << ", " << float3.f[2] << endl;
   
   //For completeness' sake
   Floats floats = otherFunc(2);
   cout << floats.x << ", " << floats.y << ", " << floats.z << endl;
   
   FloatU floatU = unionFunc(10);
   cout << floatU.f[0] << ", " << floatU.f[1] << ", " << floatU.f[2] << endl;
   //...and, like with structs, the return value can't directly be stored/copy-constructed into a writeable fixed-size array
   
   vector<float> vec = vFunc(11);
   cout << vec[0] << ", " << vec[1] << ", " << vec[2] << endl;
   
   return 0;
}

run on codepad

Turns out you need to bind the returned value to a variable in all cases, except for "possibly undefined" behaviour, and initializer lists (which would be especially useful for constructing an anonymous vector) are officially a thing of C++0x.

User avatar
e^iπ+1=0
Much, much better than Gooder
Posts: 2065
Joined: Sun Feb 15, 2009 9:41 am UTC
Location: Lancaster

Re: Coding: Fleeting Thoughts

Postby e^iπ+1=0 » Mon Apr 11, 2016 2:28 pm UTC

Makes sense, I think. Thanks for all the info, guys!
poxic wrote:You, sir, have heroic hair.
poxic wrote:I note that the hair is not slowing down. It appears to have progressed from heroic to rocking.

(Avatar by Sungura)

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Mon Apr 11, 2016 7:08 pm UTC

Code: Select all

template<class T, std::size_t N>
struct my_array {
  T raw[N];
  T* data() { return raw; }
  T const* data() const { return raw; }
  T& operator[](std::size_t i){ return data()[i]; }
  T const& operator[](std::size_t i) const { return data()[i]; }
  T* begin() { return data(); }
  T* end() { return data()+N; }
  T const* begin() const { return data(); }
  T const* end() const { return data()+N; }
  std::size_t size() const { return N; }
  bool empty() const { return false; }
  T& front() { return *begin(); }
  T const& front() const { return *begin(); }
  T& back() { return *(end()-1); }
  T const& back() const { return *(end()-1); }
};

struct empty{};
template<class T>
struct my_array<T, 0> {
  empty raw;
  T* data() { return 0; }
  T const* data() const { return 0; }
  T& operator[](std::size_t i){ return data()[i]; }
  T const& operator[](std::size_t i) const { return data()[i]; }
  T* begin() { return data(); }
  T* end() { return data()+N; }
  T const* begin() const { return data(); }
  T const* end() const { return data()+N; }
  std::size_t size() const { return 0; }
  bool empty() const { return true; }
  T& front() { return *begin(); }
  T const& front() const { return *begin(); }
  T& back() { return *(end()-1); }
  T const& back() const { return *(end()-1); }
};

The above is a first-pass implementation of `std::array` or `boost::array`.

You can return `my_array<float, 3>` from your function without any call to `new` or whatever.

To construct, use two squiggles: `{{ 1.0, 2.0, 3.14 }}`.

It is basically a ridiculously thin wrapper around a C array. A full on boost/std array has a few more functions, but I got lazy, and the above is far more than enough to be useful.

The 0 size specialization can be useful, even if nearly every operation results in UB, because empty() and size() let you avoid calling them. Adding ASSERT(false) to them (and adding similar assert checks for bounds in the non-zero sized one) is good.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
You, sir, name?
Posts: 6983
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City
Contact:

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Mon Apr 11, 2016 10:00 pm UTC

I think defining a few standard tags (at least my_array::value_type and iterator tags) and whatever will help algos interact with that implementation even more effortlessly. But for a first pass I think you've implemented more than i would have :P
I edit my posts a lot and sometimes the words wrong order words appear in sentences get messed up.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Thu Apr 14, 2016 10:27 pm UTC

Pointers are already valid random access iterators.

And I'm too lazy to expose `value_type`. Do a `std::decay<decltype(*adl_begin(std::declval<T&>()))>`, and break on `std::vector` bool like a real programmer.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Xanthir
My HERO!!!
Posts: 5425
Joined: Tue Feb 20, 2007 12:49 am UTC
Location: The Googleplex
Contact:

Re: Coding: Fleeting Thoughts

Postby Xanthir » Fri Apr 15, 2016 1:19 am UTC

You C++ people are goddam crazy.
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6598
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: Coding: Fleeting Thoughts

Postby Thesh » Fri Apr 15, 2016 2:00 am UTC

I can't even read most C++ code posted here.
Summum ius, summa iniuria.

commodorejohn
Posts: 1197
Joined: Thu Dec 10, 2009 6:21 pm UTC
Location: Placerville, CA
Contact:

Re: Coding: Fleeting Thoughts

Postby commodorejohn » Fri Apr 15, 2016 3:07 am UTC

I can follow C++ pretty well when it's just C with classes. Then they go and break out that template stuff and I run screaming back to C99.
"'Legacy code' often differs from its suggested alternative by actually working and scaling."
- Bjarne Stroustrup
www.commodorejohn.com - in case you were wondering, which you probably weren't.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Fri Apr 15, 2016 12:14 pm UTC

Xanthir wrote:You C++ people are goddam crazy.

That is `std::decay_t<decltype(std::declval<crazy&>().goddam())>` to you.
Spoiler:
std::decay_t<TYPE> takes a type and strips references and const qualifiers (making it suitable for storage), as well as does stuff to arrays and function references.

decltype(expression) tells you the type of the expression.

std::declval<crazy&>() creates a "crazy&" without actually creating a crazy.

.goddam() pretends to call the .goddam() method on the crazy reference above.

So the above is the type suitable for storage returned by taking a crazy object (in an "lvalue" (non-temporary) context) and invoking the .goddam() operator on it.

---

Note that the previous std::decay_t post, where I said I'm too lazy to provide a value_type, was a joke: I don't expect anyone to use that to get the value type of a container.

It breaking on std::vector of bool is because they screwed up when they wrote std::vector of bool, and made it a bit-packed array, and used pseudo-references to fake bit twiddling (as you cannot have a reference-to-a-bit in C++). The expression gets the type returned by dereferencing an iterator into the vector; in the case of vector of bool, this isn't a bool but rather that pseudo-reference. So the really complex way to avoid saying "container::value_type" fails on vector of bool.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Wildcard
Candlestick!
Posts: 253
Joined: Wed Jul 02, 2008 12:42 am UTC
Location: Outside of the box

Re: Coding: Fleeting Thoughts

Postby Wildcard » Sat Apr 16, 2016 3:05 am UTC

@ucim (Jose?), you are going to have a really fun time programming software that networks between spaceships moving at relativistic speeds and multiple planets.

"Time is immutable" indeed. :D

Also, more concretely:

Mark Burgess wrote:Wrapping our heads around behaviours that happen in parallel, at multiple locations, and from different available views, is hard. In science, the analysis of this is called relativity theory, and many of the great minds of philosophy have struggled with versions of it, including Galileo, Einstein and Kripke. The problem is no easier in computing, but in distributed systems we have to do it all the time.

The so-called CAP theorem was a trigger that unleashed a public discussion about this in the distributed database world, and today its name is brandished both as a badge of honour, and even as a weapon, in debates about consistency of viewpoint in distributed systems -- what Einstein called simultaneity, and what databasers call distributed consistency.

Stories about simultaneity generally end up with the same answer in these theories: simultaneity is not a helpful concept in the world, and multiple agents, players, actors, or whatever we would call them, are doomed (indeed encouraged) to see the world from unique perspectives, and be contented to disagree about its consistency. Why? Because ultimately it is the responsibility of each observer of the world to find their own consistency from their own perspective, and based on what they can observe impartially about it. Sometimes, we will be able to calculate others' perspectives from our own, but only within the limits of communication, and no faster than the rate at which messages can be sent.


Fascinating and excellent article, by the way, but not light reading. (You have been warned.)
There's no such thing as a funny sig.

User avatar
raudorn
Posts: 370
Joined: Mon Jun 13, 2011 11:59 am UTC

Re: Coding: Fleeting Thoughts

Postby raudorn » Sun Apr 17, 2016 12:02 pm UTC

Everyone knows the feeling when something that should work, doesn't. Today I got to experience the more rare feeling of something working, which shouldn't. A bit of context:

I'm writing a small interactive fiction framework, mostly used for game jams and because I can. Scenes are basically just text linked to other scenes with clickable options (which may have conditions, but those are irrelevant here). For debugging/spellchecking I wanted a back button, so I didn't have to take the entire path to get to the previous scene.

Solution: Every time I load a new scene I save the current scene and add it as an option for the following scene. I thought that this solution should at least get me back one level, which is suffcient for the purposes.

But then I noticed the button did not just take me back one level, it worked arbitrarily deep, which should be physically impossible because I'm not saving the history of scenes. I was really, really confused. A bit of experimenting later I noticed that a) the button doesn't take multiple rounds in a circle, going back only once through the circle and b) when there were multiple predecessors to a scene, it always took the one that was established first.

The second part was the missing clue: Somehow the history was indeed saved, but immutably so. Which is a symptom of invalid cache entries.

Of course. When loading a scene I'm shunting it into a "cache" (just an interval variable for the length of the game), so I don't have to load it again when the player is walking in circles. But because I was adding the back button as an option to the scene and then kept the scene around, the first encountered predecessor was saved. Basically the player built an incomplete graph of scenes while playing, which the back button was unintentionally using to navigate further back than intended.

Had me really worried, for a second I thought I may have broken some information conservation law. But it was just an instance of: "There are only two hard things in programming: Cache invalidation and naming things."

User avatar
ucim
Posts: 6888
Joined: Fri Sep 28, 2012 3:23 pm UTC
Location: The One True Thread

Re: Coding: Fleeting Thoughts

Postby ucim » Mon Apr 18, 2016 1:57 am UTC

So I have this site with a bunch of forms, and I wrote a form creator/processor that has the logic for about half of them. I have a file for each of the forms containing the form parameters, and each one #includes the logic part. The other half of the forms require some sort of special handling, so don't fit nicely into the form logic.

In each of the cases (and everywhere these forms are needed), there is a (boolean) variable called $virgin which indicates whether the data in the form has been touched or not.

I have a data validator that sets a (boolean) array element ('isok') for each element that passes, and a (boolean) variable called $allok that indicates whether all form elements pass.

So far, I'm naming things well.

So now I have a special case where I am validating a category, which is either one letter (i.e. 'A') or two letters (e.g. 'AF'). The first letter is the category, and the second is the subcategory. Based on the category, I select (serverside) an array for the dropdown list in the form. 'A' is a valid catchall subcategory.

I want to add a blank first element to the dropdown list to ensure that the user proactively picks from there and doesn't just skip over it (leaving an unchosen valid subcategory chosen). So, I created a function to do this for virgin (or mustardy) forms.

Not wanting to fard the database with a redundant column (category) when the subcategory already has that info, I had overloaded the key. But now I'm stuck.

The blank is an invalid entry, but it must not be considered invalid in a virgin form. This is already taken care of - virgin forms ignore 'isok'.

The blank (in this case) is also keyed to the category, so that if the user mustards up the data entry, I can still pick the right array for the dropdown list when I re-present the form. The blank itself however is an invalid entry, so it must be flagged as such if the user submits it that way. But being an invalid entry, it sets $allok to FALSE, which busts out of the form entirely, not letting the user fix it. (Anything could be wrong, and in non-hacking cases this doesn't come up). Except here.

I can't {this} because {reasons} and I can't {that} because {other reasons}.

So... the solution I found is to change $virgin (and 'virgin') to not be boolean, but rather, a string, which would contain 'virgin' if virgin, 'retrieve' if the data comes untouched from the database (it is treated as virgin after validation), and the empty string otherwise. This allows for other cases in the future; a kind of multi-valent boolean, as it were. This works and is molpish.

Except....

the variable is still called $virgin, but no longer represents what it looks like it should represent. And there's a seaish amount of them all throughout my program. Sed could change them all, but not all of them should be changed. (There are still other places where $virgin means what it looks like).

So, either it will be a long, "fun" refactoring, or I'll just live with a naming fail until something bigger changes.

:/

Wildcard wrote:@ucim (Jose?), you are going to have a really fun time programming software that networks between spaceships moving at relativistic speeds and multiple planets.

"Time is immutable" indeed. :D
Now, if I could get on a spaceship at relativistic speeds, and alter time, maybe I could fix this problem before it happened.

And yes, it's fine to call me Jose - that's why it's there. :)

Jose
Order of the Sillies, Honoris Causam - bestowed by charlie_grumbles on NP 859 * OTTscar winner: Wordsmith - bestowed by yappobiscuts and the OTT on NP 1832 * Ecclesiastical Calendar of the Order of the Holy Contradiction * Heartfelt thanks from addams and from me - you really made a difference.

User avatar
Flumble
Yes Man
Posts: 2262
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Mon Apr 18, 2016 7:41 am UTC

For some reason I started working on a FastCGI client implementation in GameMaker today. Don't ask. :P
It's pretty easy to implement even in the most abhorrent of languages (OK, it's not as bad as visual basic) and it allows for an easy way of encrypting sockets (assuming HTTPS is used) when all else (cryptography libraries, ssh tunnels, vpns) is unfeasible.

It's even easier when you don't have to implement half the protocol because servers like Caddy don't bother sending weird packets.
raudorn wrote:Everyone knows the feeling when something that should work, doesn't.

And of course this happened a couple of times. Most notable was seeing packets partly overwriting each other. It turns out copying buffers into a target buffer doesn't update the target buffer's seek position, unlike simply writing to it.
Also endianness. :?

User avatar
PM 2Ring
Posts: 3715
Joined: Mon Jan 26, 2009 3:19 pm UTC
Location: Sydney, Australia

Re: Coding: Fleeting Thoughts

Postby PM 2Ring » Mon Apr 18, 2016 7:57 am UTC

raudorn wrote:Everyone knows the feeling when something that should work, doesn't. Today I got to experience the more rare feeling of something working, which shouldn't.

I get uncomfortable when that happens, and if I can't prove to myself why it behaves the way it does I have to change it to something I do understand, because I know that if I don't it will surely come back and bite me one day. :)

raudorn wrote:Had me really worried, for a second I thought I may have broken some information conservation law. But it was just an instance of: "There are only two hard things in programming: Cache invalidation and naming things."

That saying comes from the late great Phil Karlton, but Leon Bambrick made it perfect:
Phil Karlton and Leon Bambrick wrote:There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Mon Apr 18, 2016 3:12 pm UTC

raudorn wrote:But it was just an instance of: "There are only two hard things in programming: Cache invalidation and naming things."

Ah yes, the old THTIPCIANT rule. But you forgot the off-by-one error.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Mon Apr 18, 2016 3:13 pm UTC

raudorn wrote:But it was just an instance of: "There are only two hard things in programming: Cache invalidation and naming things."

Ah yes, the old THTIPCIANT rule. But you forgot the off-by-one error.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

korona
Posts: 495
Joined: Sun Jul 04, 2010 8:40 pm UTC

Re: Coding: Fleeting Thoughts

Postby korona » Tue Apr 19, 2016 9:17 am UTC

I always found C++ aliasing rules to be complicated. What's even worse is that they differ from C's rules.

Is there any standard compliant way to implement functions like bind() in C++ without using memcpy() or a manual copy through char*?

Essentially I need to do something like

Code: Select all

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
    if(addr->sa_familiy == AF_INET) {
        auto real_addr = reinterpret_cast<const struct sockaddr_in *>(addr);
        // access real_addr->sin_port and real_addr->sin_addr
    }else // ...
}

but that obviously violates the aliasing rules.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Tue Apr 19, 2016 2:03 pm UTC

I thought there was a trick involving unions. Like:

Code: Select all

template<class A, class B>
struct safe_alias_t {
  union u {
    A a;
    B b;
  };
  static B* a_to_b(A* a) {
    return std::address_of(reinterpret_cast<u*>(a)->b);
  }
  static A* b_to_a(B* b) {
    return std::address_of(reinterpret_cast<u*>(b)->a);
  }
};
template<class Dest, class Src>
Dest* safe_alias( Src* src ) {
  return safe_alias_t<Src, Dest>::a_to_b(src);
}

Basically, the existence of the union `u` prevents the compiler from presuming there is no aliasing or somesuch.

Very uncertain. And might rely on standard layout compatibility stuff.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Xenomortis
Not actually a special flower.
Posts: 1455
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Tue Apr 19, 2016 4:52 pm UTC

Stack overflow suggests the union trick to reinterpret bytes was only made legal in C99 (so there's a chance it never made it to C++).
Although GCC insists it's provided as an "extension"?
Image

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Tue Apr 19, 2016 5:57 pm UTC

Oh, and if `sockaddr_in` and `sockaddr` are layout compatible in C++, then the direct reinterpret cast should be legal. The fields in one will refer to the fields in the other.

If they are not, well, that isn't good.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Xanthir
My HERO!!!
Posts: 5425
Joined: Tue Feb 20, 2007 12:49 am UTC
Location: The Googleplex
Contact:

Re: Coding: Fleeting Thoughts

Postby Xanthir » Fri Apr 22, 2016 4:25 am UTC

Starting up coding in Blink again (the layout engine for Chrome), and *wow* is my C++ knowledge out-of-date.

But for serious, tho, wtf is up with C++'s syntax? In what world is

Code: Select all

SomeClass foo(arg1, arg2);


a reasonable way to call the SomeClass constructor with (arg1, arg2) and store it in a variable named "foo"?

That is, modulo some funkiness with moves, it's equivalent to:

Code: Select all

SomeClass foo = SomeClass(args1, arg2);


and that's DUMB.

I think I'm just spoiled by languages with relatively consistent syntax (Lisp, JS, Python, Haskell-if-you-ignore-record-constructors).
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6598
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: Coding: Fleeting Thoughts

Postby Thesh » Fri Apr 22, 2016 4:36 am UTC

I don't really have a problem with that, because there is no copying involved (i.e. you are allocating space for foo on the stack, and passing a pointer to foo to the constructor).
Summum ius, summa iniuria.

User avatar
Xanthir
My HERO!!!
Posts: 5425
Joined: Tue Feb 20, 2007 12:49 am UTC
Location: The Googleplex
Contact:

Re: Coding: Fleeting Thoughts

Postby Xanthir » Fri Apr 22, 2016 5:24 am UTC

Yeah, there's clearly nothing wrong with the *mechanics* involved. It's the *syntax*. "foo(arg)" is, in every other place in the platform, either a syntax construct named "foo" or a function call for a "foo" method. Except in this one place, where it's declaring a variable that will store the results of a function call that is magically invoked without actually using the function's name anywhere (except indirectly, in the type declaration for the variable).
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

User avatar
phlip
Restorer of Worlds
Posts: 7573
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Fri Apr 22, 2016 6:17 am UTC

Code: Select all

struct A { A(int) {} };
int x;
typedef int y;

A foo(x), bar(y);

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

User avatar
Xenomortis
Not actually a special flower.
Posts: 1455
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Fri Apr 22, 2016 9:19 am UTC

Xanthir wrote:Starting up coding in Blink again (the layout engine for Chrome), and *wow* is my C++ knowledge out-of-date.

But for serious, tho, wtf is up with C++'s syntax? In what world is

Code: Select all

SomeClass foo(arg1, arg2);


a reasonable way to call the SomeClass constructor with (arg1, arg2) and store it in a variable named "foo"?

That is, modulo some funkiness with moves, it's equivalent to:

Code: Select all

SomeClass foo = SomeClass(args1, arg2);


and that's DUMB.

I think I'm just spoiled by languages with relatively consistent syntax (Lisp, JS, Python, Haskell-if-you-ignore-record-constructors).


Doesn't seem any less weird than

Code: Select all

SomeClass (*foo)(int, int);

Although I do think C's function pointer declarations *are* weird.
Last edited by Xenomortis on Fri Apr 22, 2016 9:23 am UTC, edited 1 time in total.
Image

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Fri Apr 22, 2016 9:20 am UTC

The joke is that one is a variable, the other a function decl.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 9 guests