I think this depends on the early implementations of the Pascal language and its magic system functions... and was never changed afterwards. In general, the fewer keywords the less they come your way in terms of naming and conflicting. Introducing new keywords is particularly risky, as it will invariably break someone code.
Marco Cantù I understand that adding keywords is not something that should be done careless, but some things do deserve to be keywords, like weak, break, continue...
And if anyone's code would be broken because of they use those as identifiers I can only say they get what they deserve ;-)
Marco Cantù It makes code more readable and intent clearer.
I'll take weak over [weak] any time. This is less of issue with break and continue, but those are basic flow instructions and I don't see any reason why they would not be keywords. In most languages they are.
BTW, I am not suggesting that you should jump and add those to compiler right now... ok weak would be nice, actually, more than nice...
Marco Cantù [weak] vs weak is huge difference, those brackets are very annoying for both reading and writing.
Also, with keywords you get special code highlighting (in my case bold) and that makes keywords really stand out. That is the difference you get with Break vs break
As far as intent, like I said break and continue are not regular functions, they are controlling the flow and because of that they fall into same category as if, then, else, repeat, while, for, do...
"program", "unit" and "library" do not really need to be reserved keywords, they have meaning only as the first token of a source file, they should not have any special meaning elsewhere.
BTW the IDE highlighter still think that Index is a keyword in "property Items[Index: Integer]" and that "message" is a keyword anywhere.
Marco Cantù I understand that adding keywords might break peoples code. But finding "workarounds" to extend the language makes the language very inconsistent. Explain to someone without mentioning some internal details of the implementations why some things are keywords like var, out, const and others have to be attributes (like volatile, weak, unsafe, ref). A big part of the ease to understand a language depends on its consistency. And nowadays we find these inconsistencies all over the place in object pascal (tell me about arrays and when to use square or round brackets...).
Marco Cantù[weak] vs weak is a massive difference. The first one says "oh yeah this pointer here is weak btw, dunno if you care or not, just thought I'd mention it". The second one says "hey, here's a weak pointer, treat it as such".
Marco Cantù In addition to what Stefan Glienke said, you kind of lost the right to use "breaking code" as excuse after removal of 8-bit strings from mobile compilers and whole ZBS mess ;-)
Dalija Prasnikar To be fair they never removed it from these platforms, these platform never had them. So it's a bit of a difference to introduce a new compiler target that is missing some features than to remove them from an existing one.
Stefan Glienke To be fair they are still there, just unreachable to us mere mortals.
Yes, there is a bit of difference between removing something from existing compiler and removing something from brand new compiler for another platform.
But they are selling single source cross-platform solution. Breaking code between platforms without firm technical reasons, still counts as breaking code, at least in my book.
If those were added as keywords, lots of code would break. Even adding them as directives would break things. Languages try to have as few of those as possible for a reason.
Marco Cantù A keyword prevents users from overriding inherent functionality, for one. Imagine if someone imported a unit that ended up overriding "break"!
Stefan Glienke Don't forget the answer to the question "Are variables initialized when declared in Delphi"?
One answer I saw to this question went like this:
>When you create a local variable (var MyVar: >Integer), its initial value is undefined. It will >have the value of whatever was in that >memory location from before. You should >always assign it a value when using it, >except…. >Local reference-counted variables (Strings, >Interfaces, dynamic arrays) ARE initialized >with an “empty” value (empty string, nil, >etc…). > >When you create a new object (i.e. MyVar := >TMyObject.Create), all of the fields of the >object are initialized to 0 or “empty.” Any >numeric fields are zero, strings are empty >strings, references to other objects, >interfaces, etc… are nil. Boolean fields are >false. > >GLOBAL variables (in the var section of a >unit, not the var section of a procedure or >function) are initialized to 0 or empty when >the application starts.
Maybe it's even more complex now.
Oh, and "records with methods" vs. classes. If you were designing the language from scratch you'd never have both. Records with methods are a subset of classes. But Delphi needed operator overloading and that couldn't easily be done without automatic memory management and that couldn't be added to classes without rewriting the ancient desktop compiler which wasn't going to happen so.... we got records with methods, which is just one more thing to confuse new users.
I 1000% agree with you. At some point the technical debt needs to be paid and there needs to be some compatibility breaks to clean up the language. It hurts for a while, but it has to be done. If it isn't, you get things like the current state of Java, where people create frameworks to deal with the complexity and are now proposing new frameworks to sit on top of the other frameworks because even the frameworks are getting too unwieldy.
I remember Marco proposed cleaning up lots of things when there was talk about a new desktop compiler that didn't end up happening. He said you wouldn't expect a new VW Beetle to be able to use the same parts from the original Beetle.
Joseph Mitzen the rule, 'the fields of a class and any global variables (including class vars) are zero-initialised, but local variables are not' is good enough for someone new to the language IMO. Personally I'd zero-initialise everything, but there's not been any particular changes here since Delphi 2 in 1996 (class vars are just globals with restricted access).
'Oh, and "records with methods" vs. classes. If you were designing the language from scratch you'd never have both.' Surely C# falsifies that statement...?
Joseph Mitzen There are many situations where a record with methods is to prefer before classes. In time-critical parts, you can avoid hitting the heap for example.
Joseph Mitzen I've had clients with global methods called break and exit causing uncountable bugs. They refused to change the names. Note the had, not have.
Chris Rolliston Yes, C# structs are an exception - I wonder if it's because they share Anders in common?
MS gives this advice for choosing between a struct and a class:
>Do not define a structure unless the type has >all of the following characteristics: >It logically represents a single value, similar >to primitive types (integer, double, and so on). >It has an instance size smaller than 16 bytes. >It is immutable. >It will not have to be boxed frequently.
This looks like an Anders-style "optimization" at the expense of simplicity. The struct is immutable and value type vs. reference, etc. There's still no high-level need for both, and certainly not in Delphi.
Leif Uneus But would you ever design it that way in the first place? That's a micro-optimization at the expensive of language complexity and clarity.
If you were designing the language today you'd have ARC by default, be able to use operator overloading for classes. Following modern design principles, your native data types such as string and array would be classes too. There'd be no need for "record helpers", and no need for introducing records with methods.
Joseph Mitzen Please troll harder - one minute you're claiming C++ is brilliant and wondering why Delphi can't be more like it, the next you're moaning about 'language complexity and clarity'.
Slightly off topic, +1 on comments does not seem to work properly. I know I have +1 some comments, and now some +1 are gone. Has anyone else seen that?
Exit too
ReplyDeleteBecause when it was added to the language, nobody wanted to change the compiler?
ReplyDeleteI would have thought that a compiler change would be required to support the functionality.
ReplyDelete"Exit" could be because you have "Exit()"...?
I think this depends on the early implementations of the Pascal language and its magic system functions... and was never changed afterwards. In general, the fewer keywords the less they come your way in terms of naming and conflicting. Introducing new keywords is particularly risky, as it will invariably break someone code.
ReplyDelete/sub
ReplyDeleteBTW many yeas ago I used Pascal compiler which implemented Exit as Delphi now implements Break (Exit from the current loop).
ReplyDeleteMarco Cantù I understand that adding keywords is not something that should be done careless, but some things do deserve to be keywords, like weak, break, continue...
ReplyDeleteAnd if anyone's code would be broken because of they use those as identifiers I can only say they get what they deserve ;-)
> some things do deserve to be keywords
ReplyDeleteWhy?
Marco Cantù It makes code more readable and intent clearer.
ReplyDeleteI'll take weak over [weak] any time. This is less of issue with break and continue, but those are basic flow instructions and I don't see any reason why they would not be keywords. In most languages they are.
BTW, I am not suggesting that you should jump and add those to compiler right now... ok weak would be nice, actually, more than nice...
> It makes code more readable and intent clearer.
ReplyDeleteUhm, I think I disagree. Break vs. break. [Weak] vs. weak... I don't see a difference in clarity and intent.
Marco Cantù [weak] vs weak is huge difference, those brackets are very annoying for both reading and writing.
ReplyDeleteAlso, with keywords you get special code highlighting (in my case bold) and that makes keywords really stand out. That is the difference you get with Break vs break
As far as intent, like I said break and continue are not regular functions, they are controlling the flow and because of that they fall into same category as if, then, else, repeat, while, for, do...
"program", "unit" and "library" do not really need to be reserved keywords, they have meaning only as the first token of a source file, they should not have any special meaning elsewhere.
ReplyDeleteBTW the IDE highlighter still think that Index is a keyword in "property Items[Index: Integer]" and that "message" is a keyword anywhere.
Dalija Prasnikar
ReplyDeleteI agree absolutly with you. I also don't like MyFunction(const [Ref] aParameter). It makes the language also confusing. FPC introduced constref as keyword: http://wiki.freepascal.org/FPC_New_Features_2.6.0#Constref_parameter_modifier
Marco Cantù I understand that adding keywords might break peoples code.
ReplyDeleteBut finding "workarounds" to extend the language makes the language very inconsistent. Explain to someone without mentioning some internal details of the implementations why some things are keywords like var, out, const and others have to be attributes (like volatile, weak, unsafe, ref). A big part of the ease to understand a language depends on its consistency. And nowadays we find these inconsistencies all over the place in object pascal (tell me about arrays and when to use square or round brackets...).
Marco Cantù[weak] vs weak is a massive difference. The first one says "oh yeah this pointer here is weak btw, dunno if you care or not, just thought I'd mention it". The second one says "hey, here's a weak pointer, treat it as such".
ReplyDeleteMarco Cantù In addition to what Stefan Glienke said, you kind of lost the right to use "breaking code" as excuse after removal of 8-bit strings from mobile compilers and whole ZBS mess ;-)
ReplyDeleteDalija Prasnikar To be fair they never removed it from these platforms, these platform never had them. So it's a bit of a difference to introduce a new compiler target that is missing some features than to remove them from an existing one.
ReplyDeleteStefan Glienke To be fair they are still there, just unreachable to us mere mortals.
ReplyDeleteYes, there is a bit of difference between removing something from existing compiler and removing something from brand new compiler for another platform.
But they are selling single source cross-platform solution. Breaking code between platforms without firm technical reasons, still counts as breaking code, at least in my book.
Stefan Glienke I know that sometimes my views may look contradictory.
ReplyDeleteFrom one side I am firmly trying to protect code compatibility and from other I am all for breaking things hard in order to get new better things.
But actually, there is no contradiction at all. You can break anything you like as long as you can show me how can I profit from that ;-)
If those were added as keywords, lots of code would break. Even adding them as directives would break things. Languages try to have as few of those as possible for a reason.
ReplyDeleteAbout syntax highlighting of keywords: CnPack IDE Wizards does a very good job highlighting Exit, Break and Continue. I find it very convenient.
ReplyDeleteMarco Cantù A keyword prevents users from overriding inherent functionality, for one. Imagine if someone imported a unit that ended up overriding "break"!
ReplyDeleteStefan Glienke Don't forget the answer to the question "Are variables initialized when declared in Delphi"?
ReplyDeleteOne answer I saw to this question went like this:
>When you create a local variable (var MyVar:
>Integer), its initial value is undefined. It will
>have the value of whatever was in that
>memory location from before. You should
>always assign it a value when using it,
>except….
>Local reference-counted variables (Strings,
>Interfaces, dynamic arrays) ARE initialized
>with an “empty” value (empty string, nil,
>etc…).
>
>When you create a new object (i.e. MyVar :=
>TMyObject.Create), all of the fields of the
>object are initialized to 0 or “empty.” Any
>numeric fields are zero, strings are empty
>strings, references to other objects,
>interfaces, etc… are nil. Boolean fields are
>false.
>
>GLOBAL variables (in the var section of a
>unit, not the var section of a procedure or >function) are initialized to 0 or empty when
>the application starts.
Maybe it's even more complex now.
Oh, and "records with methods" vs. classes. If you were designing the language from scratch you'd never have both. Records with methods are a subset of classes. But Delphi needed operator overloading and that couldn't easily be done without automatic memory management and that couldn't be added to classes without rewriting the ancient desktop compiler which wasn't going to happen so.... we got records with methods, which is just one more thing to confuse new users.
I 1000% agree with you. At some point the technical debt needs to be paid and there needs to be some compatibility breaks to clean up the language. It hurts for a while, but it has to be done. If it isn't, you get things like the current state of Java, where people create frameworks to deal with the complexity and are now proposing new frameworks to sit on top of the other frameworks because even the frameworks are getting too unwieldy.
I remember Marco proposed cleaning up lots of things when there was talk about a new desktop compiler that didn't end up happening. He said you wouldn't expect a new VW Beetle to be able to use the same parts from the original Beetle.
Joseph Mitzen the rule, 'the fields of a class and any global variables (including class vars) are zero-initialised, but local variables are not' is good enough for someone new to the language IMO. Personally I'd zero-initialise everything, but there's not been any particular changes here since Delphi 2 in 1996 (class vars are just globals with restricted access).
ReplyDelete'Oh, and "records with methods" vs. classes. If you were designing the language from scratch you'd never have both.' Surely C# falsifies that statement...?
Joseph Mitzen There are many situations where a record with methods is to prefer before classes. In time-critical parts, you can avoid hitting the heap for example.
ReplyDeleteLeif Uneus One does not exclude the other. Isn't that what C++ does with its stack allocated objects?
ReplyDeleteJoseph Mitzen I've had clients with global methods called break and exit causing uncountable bugs. They refused to change the names. Note the had, not have.
ReplyDeleteChris Rolliston Yes, C# structs are an exception - I wonder if it's because they share Anders in common?
ReplyDeleteMS gives this advice for choosing between a struct and a class:
>Do not define a structure unless the type has
>all of the following characteristics:
>It logically represents a single value, similar >to primitive types (integer, double, and so on).
>It has an instance size smaller than 16 bytes.
>It is immutable.
>It will not have to be boxed frequently.
This looks like an Anders-style "optimization" at the expense of simplicity. The struct is immutable and value type vs. reference, etc. There's still no high-level need for both, and certainly not in Delphi.
Leif Uneus But would you ever design it that way in the first place? That's a micro-optimization at the expensive of language complexity and clarity.
ReplyDeleteIf you were designing the language today you'd have ARC by default, be able to use operator overloading for classes. Following modern design principles, your native data types such as string and array would be classes too. There'd be no need for "record helpers", and no need for introducing records with methods.
Joseph Mitzen Please troll harder - one minute you're claiming C++ is brilliant and wondering why Delphi can't be more like it, the next you're moaning about 'language complexity and clarity'.
ReplyDeleteSlightly off topic, +1 on comments does not seem to work properly.
ReplyDeleteI know I have +1 some comments, and now some +1 are gone. Has anyone else seen that?
Dalija Prasnikar you still have my +1 for 8bit strings :)
ReplyDeletethere's a trick to use reserved keywords anyway
ReplyDeletefunction &exit(): string;
begin
Result := 'exit';
end;
function &break(): string;
begin
Result := 'break';
end;
procedure TForm1.FormCreate(Sender: TObject);
var
&program: string;
begin
&program := &exit() + &break();
ShowMessage(&program);
end;
Paul TOTH Now I have +1 your comments, I hope they will stick :)
ReplyDeleteChris Rolliston I'm not sure what you're referring to; I never mentioned C++ anywhere in this thread that I can see.
ReplyDeleteJoseph Mitzen ah, sorry, I've confused you with someone else! My apologies.
ReplyDelete