Did anyone read? I hope you see how it is nothing like a strong typedef (as its 
called). To me it seems like the strong one is too similar to a class to be 
worth adding, especially after reading that paper, it seems like it would allow 
new-php-user like behaviour of EVERYTHING IS A CLASS but with types, we've all 
been there. While this could stop some errors ... I've discussed this already.

Alec
I am eager to see what you guys think, this is a 'feature' I've wanted for a 
long time and you all seem approachable rather than the distant compiler gods I 
expected. 

I can also see why 'strong typedefs' were not done, it tries to do too much 
with the type system and becomes very object like....

Alec Teal <a.t...@warwick.ac.uk> wrote:

>On 23/01/13 23:07, Lawrence Crowl wrote:
>> On 1/23/13, Jonathan Wakely <jwakely....@gmail.com> wrote:
>>> On 23 January 2013 09:15, Alec Teal wrote:
>>>> I was fearful of using the word attribute for fear of getting it wrong?
>>>> What
>>>> is "this part" of the compiler called
>>> I think attributes are handled in the front end and transformed into
>>> something in the compiler's "tree" data structures.
>>>
>>> FWIW I've usually seen this feature referred to as "strong typedefs".
>>> That brings to mind the "strong using" extension G++ had for
>>> namespaces, which (prior to getting standardised as "inline
>>> namespaces") used __attribute__((strong)) so that attribute already
>>> exists in the C++ front end:
>>> http://gcc.gnu.org/onlinedocs/gcc/Namespace-Association.html
>> Note that there is a proposal before the C++ standard committee on
>> just this topic.  Consider its semantics when implementing.
>>
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf
>>
>After reading that it doesn't seem like the same thing, they are talking 
>about - essentially - creating "classes" to handle types with no runtime 
>overhead, they want to be certain the optimizer got rid of it or save 
>the optimizer a job. I'm not saying that's bad I just think it is 
>separate. Typdefs are supposed to be an alias, yes in light of that the 
>title of "type definition" seems a little misleading when put with that 
>paper, but none the less a typedef is an alias.
>
>While reading the book "The design and evolution of C++" (I am not 
>saying this to throw around "look, from the 'founder' of C++'s mouth!", 
>I read it so I could learn why things are the way they are and errors 
>which would have happened if things had of happened differently, wow 
>that's a weird sentence, I mean failed attempts) I did enjoy reading 
>about the strict typing that C++ introduced and that was to catch errors.
>
>The paper has a point, you would never try to multiply two game scores, 
>so why have compiler tell you if you do? You'd surely mean it! What if 
>you want to computer the geometric mean (or something, go with me) 
>ultimately it's still an int! Why not go a step further and give the 
>compiler the concept of a group (algebraic structure see [1]) this could 
>stop divisions by zeros! Why not say you can no longer divide an integer 
>by another integer? MOST of the time the result wont be an integer, with 
>their example of cartesian(3) to spherical coordinates you shouldn't 
>have to rigidly define such stuff that it throws an error when you do 
>something as silly as mix them up and again, when they define x there is 
>no one-size-fits-all definition for how x operates with other types. If 
>you were to seriously try you'd just get so much spam, the only reason 
>the idea doesn't totally implode is because you can "cast" back to the 
>"base", so if all your definitions - which are more like conditions - 
>don't allow something, you just side-step it, this is an own goal the 
>point was you would never sidestep.
>
>There is a line between what I am proposing and what they are, I cannot 
>define exactly where it is, by their own admitance they cant:
>
>/"This issue has been one of the consistent stumbling blocks in the 
>design of an opaque typedef//
>//facility. In particular, we have come to realize that there is no one 
>consistent approach to the//
>//return type issue such that it will meet all expectations under all 
>circumstances//:"/
>
>If they could this would be far more important than a proposed C++ 
>feature and would have been 'discovered' during the Abstract Algebra 
>boom during the times of Gauss.
>
>
>Back on topic!
>I always thought of a hard-typedef as an extension of this. I don't want 
>it treated like a class, I don't want this to be valid:
>
>----------------------------------------
>hard typdef int BookId;
>int x = 5;
>BookId my_book = x; //should fail
>BookId alternate = (BookId) x; //fine - no runtime overhead because it's 
>just an alias, no compiling overhead really either.
>----------------------------------------
>
>This (in the world of classes) is interesting because if anything int is 
>the parent of BookId, but I shouldn't need a constructor or a 
>reinterpret_cast (however it'd be applicable) because I had written 
>"(BookId)" before the x, and that's probably not an accident the 
>compiler should realize I meant to do it.
>
>Now what about the other way?
>
>----------------------------------------
>hard typdef int BookId;
>BookId x = 5;
>int my_book = x; //should fail
>int alternate = (int) x; //fine - no runtime overhead because LOOK!
>----------------------------------------
>
>Now in terms of inheritance we have it going both ways, so while you 
>could look at this as typdef system as "a set of classes all storing one 
>member of the same type with a different set of operations" you cannot 
>have implicit conversions both ways! It just makes no sense, yes it can 
>stop you writing stupid things anyway, but what use is there in defining 
>"denominator" to be nonzero or what about composite types I would never 
>want to multiply a real by an imaginary except inside the complex number 
>multiply function, what if I just want to deal with the imaginary part, 
>should I use their system and create this new imaginary type to be a 
>single number.... so forth, the document does talk about this and uses 
>the words "public" "private" and "protected" to talk about how to 
>restrict what can be done, just no, take this quote:
>
>"The programmer can similarly define a trampoline with = delete whenever a
>particular combination of parameter types ought be disallowed."
>
>In their example they delete the * operation from their 'opaque typedef' 
>for "energy"
>
>energy something = (energy) ((double) e1* (double) e2);
>
>Just... no, that works around the thing they tried to do and looks awful!
>
>
>That lack of one true way, the lack of "grand unified theory", and 
>ultimately don't forget GIGO, if you write stuff that swaps vector 
>components back it wont work. You can see how I struggle to define my 
>own line, C++'s stuff over C is not "one size fits all" but there's very 
>little specialization, where as the above allows for stupid amounts of it
>
>Back on topic!
>Solution! No implicit 'casts'!
>You could define implicit casts to be one way (up or down if you will) 
>or only with certain data-types to make writing stuff look a bit nicer 
>and involve less key-strokes but it can quickly become daft, one of the 
>other things I like about C++ is a quote from it's 'founder' "if it's an 
>ugly thing to do writing it should look ugly" or something to that 
>effect (talking about the various casts), so suppose you have this:
>
>Just generic db access stuff - how one might do it now (you could use a 
>struct, just go with it, this isn't about best practices in /that/ 
>sense), strings are database field names.
>-------------------------------------
>int book = cursor.get_int("BookId");
>int out_to = cursor.get_int("MemberId")
>-------------------------------------
>
>This should not be allowed, ERROR by default, not warning, that's the 
>point:
>-------------------------------------
>hard typdef int BookId;
>hard typdef int MemberId;
>BookId book = cursor.get_int("BookId");
>MemberId member = cursor.get_int("MemberId");
>-------------------------------------
>as it involves implicit casts, it looks nicer yes but it is still an int 
>to a BookId, also BookId looks much better in my IDE font, I've 
>developed my own styles over the years (working alone) please don't take 
>this as "CamelCase? This bitch isn't worth listening to, I know C(++) 
>people prefer _ but I'm so used to types being capital first... yeah, 
>I'll learn! Promise!
>
>This should be fine:
>-------------------------------------
>hard typdef int BookId;
>hard typdef int MemberId;
>BookId book = (BookId) cursor.get_int("BookId");
>MemberId member = (MemberId) cursor.get_int("MemberId");
>-------------------------------------
>
>and going the other way (this is pure pseudo-C++)
>-------------------------------------
>values.add("someInt",(int) someHardTypedefedTypeOfAnInt);
>db.insert("table",values);
>-------------------------------------
>
>
>
>*Note about ugliness:
>*The point is that when you do this 'cast' you mean it, this stops you 
>from balsing stuff up, like using a MemberId where you mean BookId and 
>overloading (next thing ) you shouldn't have to type a lot though just 
>something to tell the compiler "I mean to write this".
>I recently (and loved!) creating a scripting language for my work (mass 
>backspace, too far off topic even for me!) that had some static typing 
>(dynamic if unspecified) it wasn't really a speedup, it was very Lua 
>like in syntax but arrays started at 0, were not maps (there was a map) 
>and != was there instead of Lua's annoying ~=, anyway, rather than 
>writing "BookId x = (BookId) some_int;" I just wanted to tell the 
>compiler "I am aware that I am doing this" and I used "(~)" it parsed 
>this as a cast, I'd like to use this, so you could (if this were C++ 
>now) write:
>
>
>-------------------------------------
>hard typdef int BookId;
>hard typdef int MemberId;
>BookId book = (~) cursor.get_int("BookId");
>MemberId member = (~) cursor.get_int("MemberId");
>-------------------------------------
>
>I'll be honest, the main reason for this was my OCD powers of 
>doing-things-I-know-are-silly-or-else-cry so I could continue using tab 
>to align the equals signs without some variable length thing after. But 
>did it work or what!
>
>*Casts to things it's (the hard-typedef) not an alias of
>*Well this is easy, the exact same way as the "base" type, keeping with 
>my BookId and MemberId as ints:
>
>float f = (~) some_book; //error, for so many reasons, (~) relies on the 
>relation of equality between hard-typedefs ONLY, there is no reason for 
>the compiler to 'replace' (~) with (int) or (MemberId)
>//if anything the error should be generated from falling back to the 
>base type, will explain more shortly.
>
>float f = (float) some_book; //fine, you must intend a cast
>
>float f = (float) (~) some_book; //redundant, equiv to the above, but 
>still fine. - technically this is the correct way but as mentioned, a 
>cast is clearly intended in the above statement.
>
>as you know the float-int cast normally looks like this:
>float f = (float) i;
>HOWEVER there is no cast from a MemberId to a float, do what is 
>expected, be a normal typdef, you may think "Ah! Alec this voids your 
>own rule of implied types" but wait, sort of yes! But a cast is CLEARLY 
>intended.
>
>Now what about the other way?
>int i = f; //f is some float
>is truncating, we all know this, this is an implicit thing.
>
>consider two hard typedefs now, of length, area and volume (3 
>real-valued units) this does seem kind of like the paper I'm not very 
>happy with and this type information should usually be carried in the 
>variable name but I can't think of any other examples, anyway:
>
>the trick here is to realise that it's not about being pedantic, length 
>l = 0.5; is unambiguous, this behavior will not always apply, remember 
>again that (~) is short hand for "any possible cast that'd work within 
>this group of hard-typedefs"
>
>length l = 5.0; //yes I know of the implicit cast from double to float 
>AND THEN to length, but it's a constant this is therefore fine, I could 
>formally define this but c'mon, that's just being a total pedant 
>(required later, but not now)
>volume v = (~) l; //fine
>volume v = (float) l; //NOT fine the point is volume is not a float
>int k = v; //NOT FINE, we don't know that truncation makes sense on this 
>new type (see that line I talked about earlier?) only that it makes 
>sense for a float to be truncated
>int k = (~) v; //fine
>int k = (int) v; //fine because you clearly intend to cast.
>int k = (int) (~) v; //fine, technically correct
>int k = (int) (float) v; //what the above will "become"
>int k = (int) (float) (length) (~) (~) (length) (float) (volume) (float) 
>v; //POINTLESS, but still valid, there is no 'correct' (~) as it just 
>means "one that exists that'd work here"
>
>*Is there a hierarchy of typedefs?*
>obviously not, but it's worth thinking about why.
>
>hard typedef int BookId;
>hard typedef BookId MemberId;
>hard typedef int AutherId;
>hard typedef RequestId BookId;
>
>Totally valid!
>
>int
>  +--BookId
>   |  +--MemberId
>   |  +--RequestId
>  +--AutherId
>
>Is the hierarchy, if any, but:
>type(MemberId) = type(BookId) = type(int)
>by the equivalence relation of equality this implies, if this is true then:
>type(MemberId) = type(int)
>so now:
>
>int
>  +--BookId
>   |  +--RequestId
>  +--MemberId
>  +--AutherId
>
>is the same heirarchy, this is not true of class-inheritance btw incase 
>anyone is thinking "wait a minute" (inheritance is more like a<b<c so 
>a<c, it DOES distinguish between parent-child and sibling relationships!)
>This does not distinguish between parent-child relationships (up/down 
>the hierarchy 'tree') and sibling relationships (same parent), infact 
>int isn't really the parent, it just happens to be the only one with 
>operations defined to allow it to interact with other types.
>
>This means that (~) can expand to any hard-typedef of it's incestuous 
>hierarchy (I don't have a word yet, group?)
>
>*If there exists a (~) it will be unique, you will never need to use two 
>casts directly after each other when 'traversing' a typedef group when 
>searching for a 'cast' to one known type*- can be proved formally
>Works great for assignments, operator overloading (consider a definition 
>for whatever(int); whatever(MemberId); whatever(BookId); how do you pick 
>one if I say whatever((~)something);)
>
>again:
>float f = (float) some_book;
>is just shorthand for:
>float f = (float) (int) some_book;
>which is the same as:
>float f = (float) (~) some_book;
>as the cast is clearly intended (you WANT a float) you may use the first 
>one given, the point is to be sure you mean to, not to be annoying.
>
>*Overloading behavior
>*EXACTLY as typedef BUT may be overloaded - unlike a typedef.
>
>that means:
>hard typedef int ArrayFlag
>
>ArrayFlag APPEND = 0;
>ArrayFlag START = 1;
>
>template<T> T& MyArray::operator[](ArrayFlag flag);
>template<T> T& MyArray::operator[](unsigned int pos); //normal 
>array-like access.
>
>Now you can do:
>MyArray<int> array;
>array[APPEND] = 5;
>
>ALSO:
>printNameOf(BookId);
>printNameOf(MemberId);
>....
>
>define operators on these types (override adding two books, 
>whatever....) and use them as separate types resting assured there will 
>be no runtime performance drop!
>
>*Lastly
>*(~) isn't very good if calling a function, like printNameOf((~) 
>(MemberId) 5); will throw an error for the same reason
>MemberId x = 5;
>printNameOf((~) x);
>will throw an error, there is no unique type. No assumptions should be 
>made here (identity cast, (~) becomes (MemberId), not even that)
>
>
>
>That is the hard typedef!
>*
>*
>
>
>Notes:
>1) Group - in algebra a group is a structure consisting of a set and a 
>binary operation, let S be a set and @ be a binary operation, a group 
>has the following properties
>* for an x,y in S x@y is also in s (closure) - implied by binary operation
>* for an x in S there exists an i (identity element) that's also in S 
>such that x@i = i@x = x (existence of identity)
>* for x,y,z in S x@(y@z) = (x@y)@z (associativity)
>* for an x in S there exists a y in S such that x@y = i (the identity 
>element) (existence of an inverse)
>
>* for an Abelian (excuse my spelling, dyslexic :/) group for an x,y in S 
>x@y=y@x and is in S also (commutativity)
>
>Quick examples:
>
>Integers (signed :P) under addition, @ = + and S is 
>{...,-3,-2,-1,0,1,2,3,...}
>
>for integers x,y and z:
>x+y is an integer
>x+0 = 0+x = x, therefore 0 is the identity and that is an integer too.
>x+(y+z) = (x+y)+z, addition is associative
>x+(-x) = 0 so -x is the inverse of x, if x is an integer is -x? yes! so 
>the inverse is in S as required
>
>x+y=y+x (commutative) - note that this would not be the case with 
>subtraction, x-y != y-x
>
>2x2 matrices of real numbers (floats sort of) under multiplication:
>
>not a group because of the inverse property, if a matrix has a zero 
>determinant it has no inverse, a requirement. To be a group S would have 
>to be defined as "4 real numbers such that ad-bc != 0"
>
>
>

Reply via email to