tag:blogger.com,1999:blog-8837899541977019574.post6138868043770361081..comments2022-11-16T14:41:56.197+01:00Comments on program begin end. // comments?: Weird code snippet #2: Generic Double Linked ListUnknownnoreply@blogger.comBlogger20125tag:blogger.com,1999:blog-8837899541977019574.post-29316828768002128442011-07-15T16:01:21.519+02:002011-07-15T16:01:21.519+02:00Ok. Got it. Not possible with todays rules and typ...Ok. Got it. Not possible with todays rules and type generation. For it to work - the ^ would have to trigger a new rule, creating one type with two referential models when the parametric type is known after an instance declaration.<br /><br />Duplicate references would need to resolve to same type instance, I guess.Lars Fosdalhttps://www.blogger.com/profile/05635001623287214775noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-1138902333307362622011-07-15T15:13:59.622+02:002011-07-15T15:13:59.622+02:00Did you not read "There would have to be a ru...Did you not read "There would have to be a rule" and " hypothetical new rule" ?<br /><br />It is obvious that I'm suggesting a way for your generic pointers to work with a new syntax rule.<br /><br />Of course it is true that "the scope is limited to the construct, hence you can reuse T as much as you like across declarations"<br /><br />But that is one of the two things that disallow the generic record pointers your article suggests.<br /><br />The other thing is that a generic type is not a real type until the T becomes an actual type argument.Corrie Engelbrechthttps://www.blogger.com/profile/12000867917050201319noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-14957827596451374322011-07-15T15:10:15.931+02:002011-07-15T15:10:15.931+02:00Yes, but every type declaration is a new beginning...Yes, but every type declaration is a new beginning. You cannot use T in a record definition, and later on refer to the SAME T in another record definition.<br /><br />See?<br /><br />In the same way, you cannot use T in a record definition, and then later refer to the SAME T in a pointer definition.<br /><br />So, in the following code:<br /><br />type<br /> TRec1<T> = record v:T; end;<br /> TRec2<X> = record v:X; end;<br /> TRec3<T> = record v:T; end;<br /><br />The first T is only for TRec1. You cannot reference that T in any of the subsequent record declarations. <br /><br />Exactly like the T <> X in the above snippet, and no record can refer to the X except for TRec2.<br /><br />And the first T (of TRec1) is NOT the same T as TRec3.<br /><br />And for that very same reason, no other type can refer to the X (or the T).<br /><br />That is why, in the following snippet:<br /><br />type<br /> TRec1<T> = record v:T; end;<br /> PRec1<T> = ^TRec1<T><br /><br />...the two T's are not the same T.<br /><br />And they can never be the same T under current Object Pascal syntactical rules.<br /><br />The addition of requiring that all generic params (the T) be unique would make it possible to correctly associate PRec1<T> with TRec1<T>, but otherwise it's impossible.<br /><br /><br />You see, a key concept to note is that the following declaration:<br />type<br /> TRec1<T> = record v:T; end;<br /><br />DOES NOT cause a type to be created.Corrie Engelbrechthttps://www.blogger.com/profile/12000867917050201319noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-86351295446602394282011-07-15T14:55:02.407+02:002011-07-15T14:55:02.407+02:00Hmm. I really don't follow you here.
AFAIK,...Hmm. I really don't follow you here. <br /><br />AFAIK, the left side T is declarative, and right side T is referential, and the scope is limited to the construct, hence you can reuse T as much as you like across declarations?Lars Fosdalhttps://www.blogger.com/profile/05635001623287214775noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-56198443738974437202011-07-15T14:38:42.924+02:002011-07-15T14:38:42.924+02:00No, I don't think you understand.
It is impos...No, I don't think you understand.<br /><br />It is impossible to compile this in Pascal:<br />type<br /> PRec<T> = ^TRec<T>;<br /> TRec<T> = record x:T; end;<br /><br />There would have to be a rule that the T must be unique across all generic type parameters in at least unit scope for this to work.<br /><br />So there would have to be a rule that this is illegal:<br /><pre><br />type<br /> TRec1<T> = record v:T; end; // the usual<br /> TRec2<X> = record v:X; end; // still ok<br /> TRec3<T> = record v:T; end; // Not ok under hypothetical new rule. T has been used already.<br /></pre>Corrie Engelbrechthttps://www.blogger.com/profile/12000867917050201319noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-1460516841774394602011-07-15T14:24:20.376+02:002011-07-15T14:24:20.376+02:00And again...
PBaseRec<T> = ^record(RBaseRec&...And again...<br />PBaseRec<T> = ^record(RBaseRec<T>);Lars Fosdalhttps://www.blogger.com/profile/05635001623287214775noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-91078195204352445162011-07-15T14:21:56.539+02:002011-07-15T14:21:56.539+02:00bah... forgot to escape the brackets again in that...bah... forgot to escape the brackets again in that last ^record(RBaseRec<T>);Lars Fosdalhttps://www.blogger.com/profile/05635001623287214775noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-7971992954415363332011-07-15T14:20:14.762+02:002011-07-15T14:20:14.762+02:00Right - I get that this doesn't work now - but...Right - I get that this doesn't work now - but I don't see how it can't be made to work technically. <br /><br />It might be complicated for a single pass compiler, but basically it is a matter of unwrapping nested declarations. Nested declarations in general are not allowed and probably for a good reason. It would quickly become possible to construct a huge dependency tree that way, but if the compiler applied the same model for records as for classes - we would get a very powerful, flexible, and type safe system for extendable memory structures.<br /><br />For a class:<br />type<br /> TBaseClass<T> = class<br /> property Value:T;<br />end;<br />you can't do<br /> TExtClass<T> = TBaseClass<T>;<br />but you can do <br /> TExtClass<T> = class(TBaseClass<T>);<br /><br />Staying with that model, it would work to allow<br />type<br /> RBaseRec<T> = record<br /> Value:T;<br /> end;<br /> PBaseRec = ^record(RBaseRec);<br /><br />The ^ is simply notation for how the instance will be referenced.<br /><br />Aggregated records would be really handy for protocol buffers.Lars Fosdalhttps://www.blogger.com/profile/05635001623287214775noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-4765849426524523682011-07-15T13:13:57.441+02:002011-07-15T13:13:57.441+02:00Hi Lars,
I was tried to correct my post, but I ha...Hi Lars,<br /><br />I was tried to correct my post, but I had network issues:( Yes, Blogger ate the angle brackets. I will try again, and explain in another way.<br /><br />Consider this:<br />type<br /> TRec1<T> = record x:T; end; // no type exists yet<br /> TRec2<T> = record x:T; end; // no type exists yet<br /><br />1. No types exist yet. This is important.<br />2. Also the T in TRec1 does not in any way relate to the T in TRec2.<br /><br />var<br /> r1 : TRec1<Integer>; // Only now is a type created<br /><br />There is nothing to link the following pointer declaration attempt to:<br />type<br /> PRec1<T> = ^TRec1<T>; // cannot compile<br /><br />This is why the following has to be done to compile:<br /><br />type<br /> TRec3 = TRec1<Integer>; // Only now, when there is actually a type argument, is a type TRec1<Integer> created<br /><br />So now only can this compile:<br />type<br /> PRec3 = ^TRec3; // Declaration can precede TRec3 as well, it will still work<br /> <br />PS: The preview showed all of the angle brackets, and all of the types correctly. I hope the actual final post will still look correct!Corrie Engelbrechthttps://www.blogger.com/profile/12000867917050201319noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-91276941696597141562011-07-15T10:46:20.973+02:002011-07-15T10:46:20.973+02:00Corrie - I think Blogger ate your <T> so it ...Corrie - I think Blogger ate your <T> so it is a bit hard to follow your example.<br /><br />But consider<br />type<br /> PLink<T> = ^TLink<T>;<br /> TLink<T> = record<br /> value: T;<br /> end;<br /><br />Are you saying that the compiler would not be able to understand how to interpret the referential integrity of a variable of the type PLink<T>?Lars Fosdalhttps://www.blogger.com/profile/05635001623287214775noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-32776151419589021652011-07-15T10:39:38.669+02:002011-07-15T10:39:38.669+02:00I didn't. At least not on the outside...I didn't. At least not on the outside...Lars Fosdalhttps://www.blogger.com/profile/05635001623287214775noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-53042354970326461482011-07-15T09:48:48.600+02:002011-07-15T09:48:48.600+02:00Lars - as I say over there, if type safety is your...Lars - as I say over there, if type safety is your utter concern, you shouldn't be using pointers at all.Chrishttps://www.blogger.com/profile/17560741389745871142noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-82406210045654994452011-07-15T01:45:30.029+02:002011-07-15T01:45:30.029+02:00Only structured types can be genericized. A pointe...Only structured types can be genericized. A pointer is not a structured type.<br /><br />When you declare:<br />type<br /> TGenRec = record x:T; end;<br /><br />nothing will happen. The compiler does accept it, because there is a parameter T and a usage x:T;<br /><br />But when you then declare:<br />var<br /> rec : TGenRec;<br /><br />a new type is created called TGenRec;<br /><br />When you try:<br />type<br /> PRec = ^TGenRec;<br /><br />There is no instance usage of T, so the parameter can never be applied in response to a type argument. <br /><br />This is why you cannot declare a pointer to a generic record.Corrie Engelbrechthttps://www.blogger.com/profile/12000867917050201319noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-10318282935094322302011-07-15T01:24:15.461+02:002011-07-15T01:24:15.461+02:00Chris - as commented on your blog - only by sacrif...Chris - as commented on your blog - only by sacrificing type safety using raw pointers - which remove the reason for using generics alltogether.Lars Fosdalhttps://www.blogger.com/profile/05635001623287214775noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-929027474053581872011-07-15T00:42:22.288+02:002011-07-15T00:42:22.288+02:00I realise what the Delete issue is, but it only ar...I realise what the Delete issue is, but it only arises due to how you've decided to code the list itself, which is weird in itself IMO (e.g., in having Add change the contents of Self 'in place' and returning a pointer to what was Self, rather than keeping Self as it is and returning a pointer to the new node). If you were to write the list more straightforwardly, Delete becomes very easy.<br /><br />As I wasn't sure how to post code in a Blogger comments box, I've blogged about the topic myself instead: http://delphihaven.wordpress.com/2011/07/14/weird-in-more-ways-than-one/Chrishttps://www.blogger.com/profile/17560741389745871142noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-84908499436761017622011-07-14T22:28:10.037+02:002011-07-14T22:28:10.037+02:00Chris - the ^TDoubleLinked<T> will not be as...Chris - the ^TDoubleLinked<T> will not be assignment compatible as the pointer type cannot be declared, hence the non-pointer ref.<br /><br />The Delete issue is that since the tail end is a non-pointer, it cannot be disposed, so you would have to shuffle data from the "neighbour" pointer reference into the List, and dispose that pointer reference instead.<br /><br />Warren - I know... would be a lot nicer if generic pointers actually were allowed.Lars Fosdalhttps://www.blogger.com/profile/05635001623287214775noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-53405084490890903302011-07-14T22:04:18.361+02:002011-07-14T22:04:18.361+02:00My eyes, they are bleeding.
WMy eyes, they are bleeding. <br /><br />WWarrenhttps://www.blogger.com/profile/04053407632823479165noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-19911420453182003502011-07-14T20:25:36.222+02:002011-07-14T20:25:36.222+02:00I don't understand the Delete issue, or more e...I don't understand the Delete issue, or more exactly, the reason List and Node are declared as TDoubleLinked rather than ^TDoubleLinked. Could you explain...?Chrishttps://www.blogger.com/profile/17560741389745871142noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-81987828683499909002011-07-14T15:37:45.433+02:002011-07-14T15:37:45.433+02:00Thanks, Stefan! Good to know!
There is a QC issue...Thanks, Stefan! Good to know! <br />There is a QC issue on it as well: http://qc.embarcadero.com/wc/qcmain.aspx?d=66584Lars Fosdalhttps://www.blogger.com/profile/05635001623287214775noreply@blogger.comtag:blogger.com,1999:blog-8837899541977019574.post-27035246521129487592011-07-14T15:27:47.474+02:002011-07-14T15:27:47.474+02:00This is a compiler bug, as Barry mentioned here: h...This is a compiler bug, as Barry mentioned here: http://stackoverflow.com/questions/793472/pointer-to-generic-typeStefan Glienkehttps://www.blogger.com/profile/09320735081289619570noreply@blogger.com