|
Absurd Alhazred posted:This is the "if you access our website you have signed the EULA" rider of type systems. No. It is a fundamental difference of approach to type systems. It is called "structural subtyping" or "row-based polymorphism". It is the kind of type system used (mostly poorly but increasingly well) by C++ template functions, rust traits, and haskell. Structural subtyping is bottom up: the identity of a type is its attributes' type (and sometimes name or position) and its methods and their signature (and sometimes their name or position) (in an object-oriented language). A polymorphic relationship is defined and fulfilled by common structure between two types. In fact, there isn't really such thing as "defining a type" in a structural subtyping system: you only define constraints on structure at the point you use a type. If you define A = {string s} and B = {string s}, these are the same because they have the same structure. It's a better metaphor to think of A and B as aliases for the type {string s} than as capital-t Types themselves: the capital-t Type is `{string s}`. Aliases are useful for condensing and reusing code - it's a lot easier to write func f(a: A) => A than func(f(a: {string s}) => {string s}) especially as types get more complex, but in a structural subtyping system these are both exactly equivalent, and exactly explicit. This principle extends to subtyping. {string s, string t} (let's alias this to B, though i'm not doing it in the preformat section to drive home that aliases are optional and types stand on their own) is a subtype of {string s} (alias it to A, same caveat as before) because, well, it is - it contains A entirely and thus can be used wherever A can be used. The more familiar approach to type systems to most programmers, evidently including you, is "nominative subtyping" or column-based polymorphism. Nominative subtyping is the approach used by C++ functions, Java pre-generics, C#, and so on. Nominative subtyping is top down: the identity of a type is established by the programmer, and then structure is bound to that name. The name is the identity. Here, if you define A = {string s} and B = {string s} these are different, because you the programmer have explicitly given them different identities. Doing func f(a: A) => A[/fixex], [fixed]func f(a: B) => B, and func f(a: {string s}) => {string s} are not equivalent, and the latter is often not allowed because the inline type definitions don't really have an identity - certainly not an identity outside the definition of the function. As with structural subtyping, the concept of programmer-established identity in a nominative system also extends to subtyping. B = {string s, string t} is not a subtype of B = {string s} because you the programmer have not told the compiler it is; you have to do B = A + {string t} or however your language spells it. Familiarity being limited to nominative typing systems is probably what leads you to thinking that the nominative subtyping equivalent is "more explicit" than the structural subtyping equivalent. To someone familiar with structural subtyping, {string s, string t} being a subtype of {string s} is certainly explicit, because hell - look at it, B explicitly contains the structure of A. If you didn't want that, you would have made it {string u, string t} or something. If your language doesn't consider the name of an attribute part of the structure of the language (which, by the way, typescript does) then you should explicitly give it a tag or something. The thing that someone who is familiar with structural subtyping considers implicit is inferred types from usage, like being able to do something like func f(a) { return g(a) }; func g(a) {return a) without explicitly specifying constraints and having the compiler just figure out that you want As in there. Criticizing a structural subtyping system because it considers types of identical shape equivalent even if they have different names is like criticizing a nominative subtyping system because it considers types of identical shape different just because they have different names. These are orthogonal designs that use completely different methods to arrive at the same goal: a sound type system that provides programmers the ability to verify parts of their programs' correctness, and provides compilers hints about how to correctly generate efficient code. Phobeste fucked around with this message at 21:48 on Sep 26, 2022 |
# ? Sep 26, 2022 21:44 |
|
|
# ? Jun 1, 2024 17:48 |
|
Analogy:C++ code:
Similarly, in structural subtyping, types have no one true name. All the names you introduce are just quick ways to refer to the same type floating in conceptual land
|
# ? Sep 26, 2022 21:55 |
|
People who use char* foo instead of char *foo are bad people.
|
# ? Sep 26, 2022 22:16 |
|
FlapYoJacks posted:People who use char* foo instead of char *foo are bad people. The horrors come from the thread.
|
# ? Sep 26, 2022 22:22 |
|
With all the stupid garbage they poured into C++20, it would have been nice if they had made * and & first class type modifiers instead of variable-attached type modifier.
|
# ? Sep 26, 2022 22:24 |
|
Absurd Alhazred posted:With all the stupid garbage they poured into C++20, it would have been nice if they had made * and & first class type modifiers instead of variable-attached type modifier.
|
# ? Sep 26, 2022 22:32 |
|
Volte posted:That would be backwards incompatible. Yes?
|
# ? Sep 26, 2022 22:36 |
|
Absurd Alhazred posted:With all the stupid garbage they poured into C++20, it would have been nice if they had made * and & first class type modifiers instead of variable-attached type modifier. What parts of what got added to c++20 do you consider stupid garbage? This isn't a gotcha I'm just curious. I like most of it but I really wish ranges didn't carry the originating type forever.
|
# ? Sep 26, 2022 22:40 |
|
Phobeste posted:What parts of what got added to c++20 do you consider stupid garbage? This isn't a gotcha I'm just curious. I like most of it but I really wish ranges didn't carry the originating type forever. Most of this is uninteresting and I don't see myself using it in my own code. Spaceship comparison! As if C++ wasn't reusing enough punctuation marks in weird ways. "Contains" as a replacement to "find"! But "find" also gives you an iterator to something to work with if it succeeds, which is usually what I want!
|
# ? Sep 26, 2022 23:13 |
|
Contains isn't replacing find. It's in addition to find.
|
# ? Sep 26, 2022 23:37 |
|
Presto posted:Contains isn't replacing find. It's in addition to find. Fine, it's not a replacement, it's just a weird addition.
|
# ? Sep 26, 2022 23:57 |
|
Absurd Alhazred posted:Fine, it's not a replacement, it's just a weird addition. Spaceship is strange, but it's entire purpose in life is to make it easy to define object ordering without having to explicitly write operator==, operator!=, operator<, operator<=, operator>, and operator>=. It is convenient for that, and you probably shouldn't use it otherwise.
|
# ? Sep 27, 2022 00:12 |
|
I frankly would prefer that the C++ ecosystem didn't get hard rebooted. I've had enough of that with .NET thank you.
|
# ? Sep 27, 2022 01:41 |
|
Absurd Alhazred posted:Fine, it's not a replacement, it's just a weird addition.
|
# ? Sep 27, 2022 01:47 |
|
Is anyone actually using modules with C++20 yet?
|
# ? Sep 27, 2022 03:28 |
|
qsvui posted:Is anyone actually using modules with C++20 yet? I don't think most compilers have implemented it. I think msvc is the farthest along but also they started with their own slightly disjoint implementation. Absurd Alhazred posted:Most of this is uninteresting and I don't see myself using it in my own code. Spaceship comparison! As if C++ wasn't reusing enough punctuation marks in weird ways. "Contains" as a replacement to "find"! But "find" also gives you an iterator to something to work with if it succeeds, which is usually what I want! My thoughts are only partially aligned with yours. C++ Concepts library: this may not be your bag since its purpose is making the structural subtyping system provided by templates easier. But if you like and are comfortable with it, concepts is an incredibly convenient way to express template substitution constraints and a regularization and implementation into the language of the old "named concepts" (like ForwardIterator) that were by and large just documentation constructs. 3-way comparisons: I wouldn't use this in like a for loop in application code but like others have said it's pretty useful to implement in a library object to define total ordering with less god drat typing... and that's sort of a theme of a lot of the other stuff here: Map contains Range-based for loop std::string functions std::to_array These things exist because incredibly simple operations that are standard in most languages are incredibly painful in c++. Those std::string functions are starts_wtih and ends_with. to_array makes it possible to initialize an array in a way that doesn't make you want to uh shall we say post in cspam. adding initializer-statements to range-based for makes it much easier to do just-in-time container definitions for small loops. these are things I will and actually have used in production or more commonly in tests since they require allocation and they own immensely. Array bounded/unbounded - useful in libraries I think New identifiers ( import, module) - Haven't used this, don't think anything implements it, remains a bit of a ???? about how useful it'll actually be Calendar and time zone library - Mostly using cpp in embedded micros so not useful Likely and unlikely attributes - pretty sick in architectures where it's relevant, c++ has been moving forward in standardizing attributes so you can do less of the insanely stupid #if GNUC #define MYORG_LIKELY __attribute__((likely)) #endif poo poo and it's so good C++ is finally in a place where the committee is passing papers that have "for fucks sake this makes everybody's lives so much easier for a pittance of implementor effort" as their rationale (see also: #embed) and it is so goddamn nice and it's stuff that's really easy to start using
|
# ? Sep 27, 2022 03:44 |
|
I don't care about any of the "major" C++20 features other than Concepts, but the "minor" ones are a giant list of things that really should have been in C++03 (or whatever version the relevant feature was added in). C++ has an absurd number of ways that it's unnecessarily annoying to use, and C++20 is finally trying to address routine ergonomics problems. No one's life is going to be changed by not having to manually define operator != any more, but it was stupid that we had to in the first place and better late than never to fix that.
|
# ? Sep 27, 2022 04:54 |
|
duck monster posted:No. It would make him my boss, for all of the mimimum time it takes to see out my contract notification period, and likely the entire teams notification period. I've told the boss that I consider it a move that would be a company killer. well that sucks, I was definitely wrong in asking if moving to project manager would mean he'd managing bureaucracy without power over engineering how was he being considered for a software eng management role and as a fallback is being moved to hardware engineering? that seems like even more of a horror
|
# ? Sep 27, 2022 07:03 |
|
take boat posted:well that sucks, I was definitely wrong in asking if moving to project manager would mean he'd managing bureaucracy without power over engineering This dude sounds like he's not just the boss's kid, he's holding the boss's kid hostage or something, jesus christ.
|
# ? Sep 27, 2022 07:06 |
|
Phobeste posted:No. It is a fundamental difference of approach to type systems. It is called "structural subtyping" or "row-based polymorphism". It is the kind of type system used (mostly poorly but increasingly well) by C++ template functions, rust traits, and haskell. Haskell is nominally typed, and doesn't support row polymorphism. You can perhaps encode it in some roundabout way via type classes, but that's cheating.
|
# ? Sep 27, 2022 08:52 |
|
FlapYoJacks posted:People who use char* foo instead of char *foo are bad people. omeg posted:The horrors come from the thread.
|
# ? Sep 27, 2022 14:10 |
|
Plorkyeran posted:I don't care about any of the "major" C++20 features other than Concepts, but the "minor" ones are a giant list of things that really should have been in C++03 (or whatever version the relevant feature was added in). C++ has an absurd number of ways that it's unnecessarily annoying to use, and C++20 is finally trying to address routine ergonomics problems. No one's life is going to be changed by not having to manually define operator != any more, but it was stupid that we had to in the first place and better late than never to fix that. The issue with all the changes around <=> and comparison reordering and stuff is that they can silently cause new and cool issues with previously valid code. It would be great if it was in for C++98/03, so that people would write valid code for it, but since we get it in C++20, it will be lot of "fun" to update everything.
|
# ? Sep 27, 2022 14:16 |
|
Xarn posted:The issue with all the changes around <=> and comparison reordering and stuff is that they can silently cause new and cool issues with previously valid code.
|
# ? Sep 27, 2022 16:25 |
|
Athas posted:Haskell is nominally typed, and doesn't support row polymorphism. You can perhaps encode it in some roundabout way via type classes, but that's cheating. Haskell is a dynamically-typed, interpreted language.
|
# ? Sep 27, 2022 17:07 |
|
Volte posted:What issues is <=> going to cause (other than a potential lexer quirk that will in practice almost never come up)? C++ code:
|
# ? Sep 27, 2022 18:15 |
|
FlapYoJacks posted:People who use char* foo instead of char *foo are bad people. Agreed. Also int& fee is wrong and int &fee is correct. The */& binds to the object, to declare two pointers you have to write * twice. (And the common coding guideline that says to only declare one name per declaration only exists because there are people who don't understand that.) Sorry, pet peeve.
|
# ? Sep 27, 2022 18:33 |
|
Zopotantor posted:Agreed. Also int& fee is wrong and int &fee is correct.
|
# ? Sep 27, 2022 18:34 |
|
Xarn posted:The output is different with C++17 and C++20. Strictly speaking the comparison operators on that type are broken even in C++17 though, since s1 < s2 is checking a fundamentally different thing than s2 > s1.
|
# ? Sep 27, 2022 18:48 |
|
Zopotantor posted:The */& binds to the object, to declare two pointers you have to write * twice. I think that coding guideline is there to discourage you from declaring a bunch of crap at the top of a function like we're still using ANSI C. I just initialize variables closest to their point of use and I've never needed to declare multiple variables in a single line.
|
# ? Sep 28, 2022 04:06 |
|
Xarn posted:The output is different with C++17 and C++20.
|
# ? Sep 28, 2022 05:03 |
|
Zopotantor posted:The */& binds to the object, to declare two pointers you have to write * twice. this is because c is nothing but a cavalcade of old, bad design choices
|
# ? Sep 28, 2022 06:27 |
|
redleader posted:this is because
|
# ? Sep 28, 2022 06:29 |
|
Untrue. Programming in general has new bad design choices, too
|
# ? Sep 28, 2022 12:35 |
|
Athas posted:Haskell is nominally typed, and doesn't support row polymorphism. You can perhaps encode it in some roundabout way via type classes, but that's cheating. Oh didn’t know, my bad. Wonder why I thought it was
|
# ? Sep 28, 2022 13:40 |
|
Phobeste posted:Oh didn’t know, my bad. Wonder why I thought it was
|
# ? Sep 28, 2022 13:55 |
|
Volte posted:Interesting example. I assume that's because the implicit conversion to const char * is tricking std::pair into thinking the spaceship operator is defined and causing it to defer to the incorrect comparison? Eh, the stdlib guarantees that it will only use the less-than operator, so that type was fine in C++17, if a bit foot-gunny. Also IIRC that is a reduced repro from QString, so it is not exactly a niche issue
|
# ? Sep 28, 2022 17:27 |
|
On one hand, I like char* foo because the type of foo is a pointer to a char, so I feel the * should be part of the type. But then whoever designed c decided that char* foo, boo; is a pointer to a char and a char, which is dumb as hell to me, so I guess putting the * with the variable communicates that.
|
# ? Sep 28, 2022 20:36 |
|
Declaring a char and a char pointer on the same line feels needlessly confusing no matter how its notated
cheetah7071 fucked around with this message at 20:45 on Sep 28, 2022 |
# ? Sep 28, 2022 20:38 |
|
cheetah7071 posted:Declaring a char and a character pointer on the same line feels needlessly confusing no matter how its notated Tired: code:
code:
code:
|
# ? Sep 28, 2022 20:40 |
|
|
# ? Jun 1, 2024 17:48 |
|
cheetah7071 posted:Declaring a char and a char pointer on the same line feels needlessly confusing no matter how its notated Well my preference here would be that char* foo, boo; declares two pointers. But sadly c was not written that way.
|
# ? Sep 28, 2022 20:51 |