Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
ultrafilter
Aug 23, 2007

It's okay if you have any questions.


fritz posted:

Why would anybody do this to themselves :

code:
template<typename T>
class B: public C<B<T>,T,0> {
  // blah
}

class A: public B<A>{
  // blah
};


:iiam:

Loop unrolling is a legitimate use case for template metaprogramming. Everything else I've seen just feels like someone showing off how smart they are. Yeah, it's kinda cool that you can get the compiler to print an error message for every prime number less than some value, but who really cares?

Adbot
ADBOT LOVES YOU

eth0.n
Jun 1, 2012

fritz posted:

Why would anybody do this to themselves :

code:
template<typename T>
class B: public C<B<T>,T,0> {
  // blah
}

class A: public B<A>{
  // blah
};


https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

Can be very useful once you get used to it.

ultrafilter
Aug 23, 2007

It's okay if you have any questions.


OK, but explain the template parameters to B now.

poemdexter
Feb 18, 2005

Hooray Indie Games!

College Slice
Several developers, team leads, and even a lead architect were in an email chain to figure out how to deal with null values in REST api json responses. I stated my case and referenced the json spec for null. They decided that null values for json fields should be represented by the string "NA" going forward.

comedyblissoption
Mar 15, 2006

You should make an addendum to their proposal that if someone really wants a field named x to be the string value "NA" instead of a null value, they should also include a boolean field in the json called x_exists set to true.

eth0.n
Jun 1, 2012

ultrafilter posted:

OK, but explain the template parameters to B now.

Both are CRTP. There's not enough there to say whether C's additional parameters are appropriate.

Loezi
Dec 18, 2012

Never buy the cheap stuff
More of a computers-are-a-horror but I was recently made aware of the fact that given an initial state of
code:
X=0, Y=0
it's possible to run the equivalent of these two threads
code:
// Thread 0
MOV X <- 1
MOV EAX <- Y
code:
//Thread 1
MOV Y <- 1
MOV EBX <- X
and have, after executing both, the state
code:
EAX = 0, EBX = 0
on most consumer hardware.

Khorne
May 1, 2002

Loezi posted:

More of a computers-are-a-horror but I was recently made aware of the fact that given an initial state of
The horror here is in the code and not the hardware.

Or perhaps in your expectation of the output of that code, because code like that is fine if you are expecting input from either state and there's a guarantee that the MOV is atomic.

edit: There's also the obvious that I overlooked, that registers are thread-local. They'll always be "0" or "whatever they are set to not from your threads" if you create two threads to execute your instructions and then check EAX and EBX from the thread that launched those other threads. I was too caught up on the assembly and parallel execution. If you're reading from the threads given, one of the registers should always be zero because you're not setting it in that thread. The register you are setting will either be 0 or 1.

Khorne fucked around with this message at 23:06 on Sep 28, 2018

JawnV6
Jul 4, 2004

So hot ...
The hardware that met your expectation would be far more horrific.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Slash posted:

Nice tip! didn't know you could do this in Chrome. This will save me literally milliseconds every day.

If you want to save even more milliseconds, instead of moving mouse all the way to address bar, right click and move a few pixels to the "search with google" menu item.

Xerophyte
Mar 17, 2008

This space intentionally left blank

Loezi posted:

on most consumer hardware.

I'm not sure I follow what the horror is. I very much hope that's the result for separate hardware threads on all x86 processors. If it were otherwise then you'd be on an x86 implementation where the logical cores share registers which is truly a horrifying concept, and if not strictly physically impossible then at least extremely slow. I sure as poo poo wouldn't want to program against that platform, not to mention try to write a compiler back-end for it.

For software threads I guess you could make your own operating system with some sort of "thread" that only stores the instruction pointer for context switching, and not the register state, the stack pointer or any of those other annoying little details that pollute the thread state on other, weaker operating systems. Starting one of those "threads" would be just like making a function call, but a function call that randomly explodes in the presence of interrupts or any form of concurrency.

b0lt
Apr 29, 2005
It's not a horror, but yes, x86's "strong" memory model allows a load to be reordered with an earlier store, as long as they reference different locations.

Presto
Nov 22, 2002

Keep calm and Harry on.
I will never understand templates as long as I live.

Dylan16807
May 12, 2010

JawnV6 posted:

The hardware that met your expectation would be far more horrific.

I'm pretty sure they meant "EAX in thread 0 and EBX in thread 1".

So they're just talking about sequential consistency, not anything horrific.

QuarkJets
Sep 8, 2008

Presto posted:

I will never understand templates as long as I live.

What's not to understand? Maybe I'll get an amusing response explaining all the ways that I'm wrong but I think templates are just a faster way of creating overloaded functions/classes for varied input types

Xerophyte
Mar 17, 2008

This space intentionally left blank

Dylan16807 posted:

I'm pretty sure they meant "EAX in thread 0 and EBX in thread 1".

So they're just talking about sequential consistency, not anything horrific.

The program as stated requires that register writes in one thread will visible when read in another thread to consistently produce any other output. Maybe that's not the intended read, I dunno. As is I'm going to go out on a limb and say that any thread implementation that successfully guarantees that behavior is going to be real horrific.

I guess you could construct an esolang based on coding for concurrent threads in a shared registry space, like a more frustrating TIS-100.

brap
Aug 23, 2004

Grimey Drawer

Loezi posted:

More of a computers-are-a-horror but I was recently made aware of the fact that given an initial state of
code:
X=0, Y=0
it's possible to run the equivalent of these two threads
code:
// Thread 0
MOV X <- 1
MOV EAX <- Y
code:
//Thread 1
MOV Y <- 1
MOV EBX <- X
and have, after executing both, the state
code:
EAX = 0, EBX = 0
on most consumer hardware.

Everyone needs to learn and understand this example before they're allowed to write multithreaded code.

Dylan16807
May 12, 2010

Xerophyte posted:

The program as stated requires that register writes in one thread will visible when read in another thread to consistently produce any other output. Maybe that's not the intended read, I dunno. As is I'm going to go out on a limb and say that any thread implementation that successfully guarantees that behavior is going to be real horrific.

I guess you could construct an esolang based on coding for concurrent threads in a shared registry space, like a more frustrating TIS-100.

X and Y are memory locations. If you had a sequentially consistent processor, either thread0:EAX or thread1:EBX would be 1.

Loezi
Dec 18, 2012

Never buy the cheap stuff

Dylan16807 posted:

I'm pretty sure they meant "EAX in thread 0 and EBX in thread 1".

So they're just talking about sequential consistency, not anything horrific.

Dylan16807 posted:

X and Y are memory locations. If you had a sequentially consistent processor, either thread0:EAX or thread1:EBX would be 1.

This, pretty much. Sorry for not making my point more clear. In my defense it was plenty late where I am.

Most people I know have been taught and make the assumption that processors are at least sequentially consistent. Under that assumption, in the code posted the only possible results from interleaving the instructions are (T0:EAX = 1, T1:EBX = 0), (T0:EAX = 0, T1:EBX = 1) and (T0:EAX = 1, T1:EBX = 1). Under this fairly standard assuption, it should be guaranteed that the result (T0:EAX = 0, T1:EBX = 0) is not possible. You can easily check this by enumerating the ways the intructions can be interleaved and noticing that they all end with at least one register containing a 1.

However, f.ex. modern X86 and AMD64 give no fucks about that kind of logic and are happy to leave you with (T0:EAX = 0, T1:EBX = 0) if you get (un?)lucky. (EDIT: To my understanding, I'm by no means an expert) this is turn means that any mutual exclusion implementations that make the assumption of sequential consistency are not valid on these architectures either.

See here for more discussion and examples: https://www.cl.cam.ac.uk/~pes20/weakmemory/cacm.pdf

To me, this was a pretty big "the computers are a horror" since it makes it really hard to reason about concurrency at all. But if y'all already knew about this, maybe this is more of an educational horror then, since these kinds of things were definitively not discussed in any of my classes, and many people I've talked with were equally surprised about this.

Loezi fucked around with this message at 09:21 on Sep 29, 2018

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.

poemdexter posted:

Several developers, team leads, and even a lead architect were in an email chain to figure out how to deal with null values in REST api json responses. I stated my case and referenced the json spec for null. They decided that null values for json fields should be represented by the string "NA" going forward.
Good to see the Peter Principle in action in your organization!

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

QuarkJets posted:

What's not to understand? Maybe I'll get an amusing response explaining all the ways that I'm wrong but I think templates are just a faster way of creating overloaded functions/classes for varied input types

Understanding what templates are supposed to do isn't the problem. It's the loving error messages.

Take this example:

code:
#include <vector>
#include <algorithm>
int main()
{
    int a;
    std::vector< std::vector <int> > v;
    std::vector< std::vector <int> >::const_iterator it = std::find( v.begin(), v.end(), a );
}
Can you spot the problem?

Here's the list of errors you're going to get with gcc (this was a code golf contest winner)
code:
In file included from /usr/include/c++/4.6/algorithm:63:0,
                 from error_code.cpp:2:
/usr/include/c++/4.6/bits/stl_algo.h: In function ‘_RandomAccessIterator std::__find(_RandomAccessIterator, _RandomAccessIterator, const _Tp&, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator*, std::vector > >, _Tp = int]’:
/usr/include/c++/4.6/bits/stl_algo.h:4403:45:   instantiated from ‘_IIter std::find(_IIter, _IIter, const _Tp&) [with _IIter = __gnu_cxx::__normal_iterator*, std::vector > >, _Tp = int]’
error_code.cpp:8:89:   instantiated from here
/usr/include/c++/4.6/bits/stl_algo.h:162:4: error: no match for ‘operator==’ in ‘__first.__gnu_cxx::__normal_iterator::operator* [with _Iterator = std::vector*, _Container = std::vector >, __gnu_cxx::__normal_iterator::reference = std::vector&]() == __val’
/usr/include/c++/4.6/bits/stl_algo.h:162:4: note: candidates are:
/usr/include/c++/4.6/bits/stl_pair.h:201:5: note: template bool std::operator==(const std::pair&, const std::pair&)
/usr/include/c++/4.6/bits/stl_iterator.h:285:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:335:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/allocator.h:122:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/allocator.h:127:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/stl_vector.h:1273:5: note: template bool std::operator==(const std::vector&, const std::vector&)
/usr/include/c++/4.6/ext/new_allocator.h:123:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::new_allocator&, const __gnu_cxx::new_allocator&)
/usr/include/c++/4.6/bits/stl_iterator.h:805:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:799:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_algo.h:4403:45:   instantiated from ‘_IIter std::find(_IIter, _IIter, const _Tp&) [with _IIter = __gnu_cxx::__normal_iterator*, std::vector > >, _Tp = int]’
error_code.cpp:8:89:   instantiated from here
/usr/include/c++/4.6/bits/stl_algo.h:166:4: error: no match for ‘operator==’ in ‘__first.__gnu_cxx::__normal_iterator::operator* [with _Iterator = std::vector*, _Container = std::vector >, __gnu_cxx::__normal_iterator::reference = std::vector&]() == __val’
/usr/include/c++/4.6/bits/stl_algo.h:166:4: note: candidates are:
/usr/include/c++/4.6/bits/stl_pair.h:201:5: note: template bool std::operator==(const std::pair&, const std::pair&)
/usr/include/c++/4.6/bits/stl_iterator.h:285:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:335:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/allocator.h:122:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/allocator.h:127:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/stl_vector.h:1273:5: note: template bool std::operator==(const std::vector&, const std::vector&)
/usr/include/c++/4.6/ext/new_allocator.h:123:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::new_allocator&, const __gnu_cxx::new_allocator&)
/usr/include/c++/4.6/bits/stl_iterator.h:805:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:799:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_algo.h:170:4: error: no match for ‘operator==’ in ‘__first.__gnu_cxx::__normal_iterator::operator* [with _Iterator = std::vector*, _Container = std::vector >, __gnu_cxx::__normal_iterator::reference = std::vector&]() == __val’
/usr/include/c++/4.6/bits/stl_algo.h:170:4: note: candidates are:
/usr/include/c++/4.6/bits/stl_pair.h:201:5: note: template bool std::operator==(const std::pair&, const std::pair&)
/usr/include/c++/4.6/bits/stl_iterator.h:285:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:335:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/allocator.h:122:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/allocator.h:127:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/stl_vector.h:1273:5: note: template bool std::operator==(const std::vector&, const std::vector&)
/usr/include/c++/4.6/ext/new_allocator.h:123:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::new_allocator&, const __gnu_cxx::new_allocator&)
/usr/include/c++/4.6/bits/stl_iterator.h:805:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:799:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_algo.h:174:4: error: no match for ‘operator==’ in ‘__first.__gnu_cxx::__normal_iterator::operator* [with _Iterator = std::vector*, _Container = std::vector >, __gnu_cxx::__normal_iterator::reference = std::vector&]() == __val’
/usr/include/c++/4.6/bits/stl_algo.h:174:4: note: candidates are:
/usr/include/c++/4.6/bits/stl_pair.h:201:5: note: template bool std::operator==(const std::pair&, const std::pair&)
/usr/include/c++/4.6/bits/stl_iterator.h:285:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:335:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/allocator.h:122:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/allocator.h:127:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/stl_vector.h:1273:5: note: template bool std::operator==(const std::vector&, const std::vector&)
/usr/include/c++/4.6/ext/new_allocator.h:123:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::new_allocator&, const __gnu_cxx::new_allocator&)
/usr/include/c++/4.6/bits/stl_iterator.h:805:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:799:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_algo.h:182:4: error: no match for ‘operator==’ in ‘__first.__gnu_cxx::__normal_iterator::operator* [with _Iterator = std::vector*, _Container = std::vector >, __gnu_cxx::__normal_iterator::reference = std::vector&]() == __val’
/usr/include/c++/4.6/bits/stl_algo.h:182:4: note: candidates are:
/usr/include/c++/4.6/bits/stl_pair.h:201:5: note: template bool std::operator==(const std::pair&, const std::pair&)
/usr/include/c++/4.6/bits/stl_iterator.h:285:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:335:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/allocator.h:122:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/allocator.h:127:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/stl_vector.h:1273:5: note: template bool std::operator==(const std::vector&, const std::vector&)
/usr/include/c++/4.6/ext/new_allocator.h:123:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::new_allocator&, const __gnu_cxx::new_allocator&)
/usr/include/c++/4.6/bits/stl_iterator.h:805:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:799:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_algo.h:186:4: error: no match for ‘operator==’ in ‘__first.__gnu_cxx::__normal_iterator::operator* [with _Iterator = std::vector*, _Container = std::vector >, __gnu_cxx::__normal_iterator::reference = std::vector&]() == __val’
/usr/include/c++/4.6/bits/stl_algo.h:186:4: note: candidates are:
/usr/include/c++/4.6/bits/stl_pair.h:201:5: note: template bool std::operator==(const std::pair&, const std::pair&)
/usr/include/c++/4.6/bits/stl_iterator.h:285:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:335:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/allocator.h:122:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/allocator.h:127:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/stl_vector.h:1273:5: note: template bool std::operator==(const std::vector&, const std::vector&)
/usr/include/c++/4.6/ext/new_allocator.h:123:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::new_allocator&, const __gnu_cxx::new_allocator&)
/usr/include/c++/4.6/bits/stl_iterator.h:805:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:799:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_algo.h:190:4: error: no match for ‘operator==’ in ‘__first.__gnu_cxx::__normal_iterator::operator* [with _Iterator = std::vector*, _Container = std::vector >, __gnu_cxx::__normal_iterator::reference = std::vector&]() == __val’
/usr/include/c++/4.6/bits/stl_algo.h:190:4: note: candidates are:
/usr/include/c++/4.6/bits/stl_pair.h:201:5: note: template bool std::operator==(const std::pair&, const std::pair&)
/usr/include/c++/4.6/bits/stl_iterator.h:285:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:335:5: note: template bool std::operator==(const std::reverse_iterator&, const std::reverse_iterator&)
/usr/include/c++/4.6/bits/allocator.h:122:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/allocator.h:127:5: note: template bool std::operator==(const std::allocator&, const std::allocator&)
/usr/include/c++/4.6/bits/stl_vector.h:1273:5: note: template bool std::operator==(const std::vector&, const std::vector&)
/usr/include/c++/4.6/ext/new_allocator.h:123:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::new_allocator&, const __gnu_cxx::new_allocator&)
/usr/include/c++/4.6/bits/stl_iterator.h:805:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
/usr/include/c++/4.6/bits/stl_iterator.h:799:5: note: template bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator&, const __gnu_cxx::__normal_iterator&)
Templates are also the biggest contributor to why the compile times are garbage in C++, as they make C++ ambiguous and context dependent to parse, so it cannot be parsed in LR(1).

You can't really work around this and write idiomatic C++ because the STL is the "standard template library" (you should look through the code in the STL if you really want to gag.) Like if you had a crazy feature that caused super long error messages whenever something went wrong and multiplied your compile time complexity, would you make it the underlying central theme of your standard library?

The only solution, I can see, is to just write the code correctly and pray you don't make a typo or misunderstand how something is supposed to work. When I was a new developer I would see poo poo like the above all the time, but as I learned the language, it just stopped happening.

return0
Apr 11, 2007
Our computer architectures class covered memory consistency and coherence models, I’m surprised to hear programmers expecting sequential consistency from x86.

Zopotantor
Feb 24, 2013

...und ist er drin dann lassen wir ihn niemals wieder raus...

Bruegels Fuckbooks posted:

You can't really work around this and write idiomatic C++ because the STL is the "standard template library" (you should look through the code in the STL if you really want to gag.) Like if you had a crazy feature that caused super long error messages whenever something went wrong and multiplied your compile time complexity, would you make it the underlying central theme of your standard library?

The only solution, I can see, is to just write the code correctly and pray you don't make a typo or misunderstand how something is supposed to work. When I was a new developer I would see poo poo like the above all the time, but as I learned the language, it just stopped happening.
Your critique of the STL model is justified and well deserved, but as someone who had to work with pre-STL C++ libraries, you'll have to pry it out of my cold, dead hands. The original STL paper was like that ray of light in Blues Brothers for me.

Xarn
Jun 26, 2015

Loezi posted:

This, pretty much. Sorry for not making my point more clear. In my defense it was plenty late where I am.

Most people I know have been taught and make the assumption that processors are at least sequentially consistent. Under that assumption, in the code posted the only possible results from interleaving the instructions are (T0:EAX = 1, T1:EBX = 0), (T0:EAX = 0, T1:EBX = 1) and (T0:EAX = 1, T1:EBX = 1). Under this fairly standard assuption, it should be guaranteed that the result (T0:EAX = 0, T1:EBX = 0) is not possible. You can easily check this by enumerating the ways the intructions can be interleaved and noticing that they all end with at least one register containing a 1.

However, f.ex. modern X86 and AMD64 give no fucks about that kind of logic and are happy to leave you with (T0:EAX = 0, T1:EBX = 0) if you get (un?)lucky. (EDIT: To my understanding, I'm by no means an expert) this is turn means that any mutual exclusion implementations that make the assumption of sequential consistency are not valid on these architectures either.

See here for more discussion and examples: https://www.cl.cam.ac.uk/~pes20/weakmemory/cacm.pdf

To me, this was a pretty big "the computers are a horror" since it makes it really hard to reason about concurrency at all. But if y'all already knew about this, maybe this is more of an educational horror then, since these kinds of things were definitively not discussed in any of my classes, and many people I've talked with were equally surprised about this.

I don't know a single multi-core arch that is sequentially consistent by default. Now, I am not a CPU uarch expert, but from what I know, x86/x64 actually provide some of the strongest guarantees of modern architectures.


As for teaching, the course I teach (C++ 101) literally covers this in the same lecture we first tell our students about std::thread and std::atomic as a reason why the should not use anything other than memory_order_seq_cst memory order, until they have much better idea what they are doing.

return0
Apr 11, 2007

Xarn posted:

I don't know a single multi-core arch that is sequentially consistent by default. Now, I am not a CPU uarch expert, but from what I know, x86/x64 actually provide some of the strongest guarantees of modern architectures.

Mehhhh https://en.wikipedia.org/wiki/Memory_ordering#In_symmetric_multiprocessing_(SMP)_microprocessor_systems

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Xarn posted:

As for teaching, the course I teach (C++ 101) literally covers this in the same lecture we first tell our students about std::thread and std::atomic as a reason why the should not use anything other than memory_order_seq_cst memory order, until they have much better idea what they are doing.

Nobody should be using atomics at all until they have a much better idea of what they’re doing.

Once they do, they should never use seq_cst.


x86 absolutely has the strongest memory model of any architecture that anyone actually ever uses.

Who gives a gently caress about z/Arch or weird SPARC variants?

rjmccall fucked around with this message at 15:58 on Sep 29, 2018

Winter Stormer
Oct 17, 2012

Bruegels Fuckbooks posted:

Understanding what templates are supposed to do isn't the problem. It's the loving error messages.

Take this example:

code:
#include <vector>
#include <algorithm>
int main()
{
    int a;
    std::vector< std::vector <int> > v;
    std::vector< std::vector <int> >::const_iterator it = std::find( v.begin(), v.end(), a );
}
Can you spot the problem?

Here's the list of errors you're going to get with gcc (this was a code golf contest winner)

I agree that templates have really awful error messages, but even the dated RHEL 7 system compiler (g++ 4.8.5) tells you this problem flat-out after only a few lines

Falcorum
Oct 21, 2010

Winter Stormer posted:

I agree that templates have really awful error messages, but even the dated RHEL 7 system compiler (g++ 4.8.5) tells you this problem flat-out after only a few lines

Compilers in general are pretty decent at template error diagnostics now, the main thing causing those error messages to be horribly long is because they try to be helpful and list the "potential alternatives that can't be used for this template instation" when outputting the error.

Unless you're trying to do something clever with template metaprogramming, in which case, you're asking for it (just use constexpr if instead of SFINAE :v: Edit: if you have a compiler that supports it that is).

MrMoo
Sep 14, 2000

Bruegels Fuckbooks posted:

Understanding what templates are supposed to do isn't the problem. It's the loving error messages.

Take this example:

code:
#include <vector>
#include <algorithm>
int main()
{
    int a;
    std::vector< std::vector <int> > v;
    std::vector< std::vector <int> >::const_iterator it = std::find( v.begin(), v.end(), a );
}
Can you spot the problem?

Yes, C++ 2003.

Presto
Nov 22, 2002

Keep calm and Harry on.

QuarkJets posted:

What's not to understand?
You mean apart from the design, the implementation, the syntax, and the aforementioned multipage error messages?

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
the simple cases of templates look way more complex than they are since you're not used to the syntax. SFINAE? throw me in an ocean i dont wanna deal with that nonsense

Absurd Alhazred
Mar 27, 2010

by Athanatos
What's a language with good generics?

Dr. Stab
Sep 12, 2010
👨🏻‍⚕️🩺🔪🙀😱🙀

Absurd Alhazred posted:

What's a language with good generics?

Go, where you use a an editor extension to cut and paste code.

ultrafilter
Aug 23, 2007

It's okay if you have any questions.


Absurd Alhazred posted:

What's a language with good generics?

Haskell.

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

Absurd Alhazred posted:

What's a language with good generics?

i like generics in C# the best. C#/java create generic objects on runtime and deal with all this poo poo using the best language feature in the history of language features, reflection.

eth0.n
Jun 1, 2012
Rust has great generics. As easy to use as Java's, but get compiled and optimized like C++ templates. They're modeled after Haskell, but not as flexible.

Carbon dioxide
Oct 9, 2012

Scala of course. Made to combine the best bits of Haskell with the best bits of Java.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Bruegels Fuckbooks posted:

Understanding what templates are supposed to do isn't the problem. It's the loving error messages.

Take this example:

code:
#include <vector>
#include <algorithm>
int main()
{
    int a;
    std::vector< std::vector <int> > v;
    std::vector< std::vector <int> >::const_iterator it = std::find( v.begin(), v.end(), a );
}
Can you spot the problem?

Here's the list of errors you're going to get with gcc (this was a code golf contest winner)

This is a 7-year-old compiler. Let's take a look at the error with something a bit more recent:

code:
In file included from <source>:1:
In file included from /opt/compiler-explorer/gcc-7.2.0/lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/vector:60:
In file included from /opt/compiler-explorer/gcc-7.2.0/lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/stl_algobase.h:71:
/opt/compiler-explorer/gcc-7.2.0/lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/predefined_ops.h:241:17: error: invalid operands to binary expression ('std::vector<int, std::allocator<int> >' and 'const int')
        { return *__it == _M_value; }
                 ~~~~~ ^  ~~~~~~~~
/opt/compiler-explorer/gcc-7.2.0/lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/stl_algo.h:120:8: note: in instantiation of function template specialization '__gnu_cxx::__ops::_Iter_equals_val<const int>::operator()<__gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> > *, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >' requested here
          if (__pred(__first))
              ^
/opt/compiler-explorer/gcc-7.2.0/lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/stl_algo.h:161:14: note: in instantiation of function template specialization 'std::__find_if<__gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> > *, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >, __gnu_cxx::__ops::_Iter_equals_val<const int> >' requested here
      return __find_if(__first, __last, __pred,
             ^
/opt/compiler-explorer/gcc-7.2.0/lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/stl_algo.h:3907:19: note: in instantiation of function template specialization 'std::__find_if<__gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> > *, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >, __gnu_cxx::__ops::_Iter_equals_val<const int> >' requested here
      return std::__find_if(__first, __last,
                  ^
<source>:7:64: note: in instantiation of function template specialization 'std::find<__gnu_cxx::__normal_iterator<std::vector<int, std::allocator<int> > *, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >, int>' requested here
    std::vector< std::vector <int> >::const_iterator it = std::find( v.begin(), v.end(), a );
Seems pretty obvious what the error is?

Eela6
May 25, 2007
Shredded Hen

Absurd Alhazred posted:

What's a language with good generics?

Rust.

Adbot
ADBOT LOVES YOU

Absurd Alhazred
Mar 27, 2010

by Athanatos
I guess I should tRust in the two votes for Rust! :v:

Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply