Hi there, this is pure curiosity only; but this compiler behaviour seems odd to me. What do you think?
Hi there, this is pure curiosity only; but this compiler behaviour seems odd to me. What do you think?
https://gist.github.com/ortuagustin/40abdd7a2ce43c47ad0fc94d15ce3fcd
https://gist.github.com/ortuagustin/40abdd7a2ce43c47ad0fc94d15ce3fcd
Reproduced on Delphi 2010, 10 Seattle and 10.1 Berlin
ReplyDeleteSeems like a glitch in the compiler recognizing that it is in fact in the scope of that class for this method so accessing a strict private/protected symbol should be allowed.
ReplyDeleteIt also happens when you access a strict private const as default value for a parameter in the implementation section of a unit (which you can omit of course but it shows the issue). So this issue is not just limited to types.
Yes. Scoping with inner stuff is very odd in general. The lack of a formal language specification makes it very hard to predict the effect of use cases or generate them for testing.
ReplyDeleteI think that it is correct because you could not make a public method with a strict private type as result, but the compilation fails also if you declare those function as strict private, and that is an error for me.
ReplyDeleteBTW the public function GetPrivate and GetProtected should not compile for the same reason.
Paul TOTH Wrong, you can:
ReplyDeleteprogram Project1;
{$APPTYPE CONSOLE}
type
TFoo = class
strict private type
TBar = class
public
procedure Baz;
end;
public
function Boo: TBar;
end;
{ TFoo }
function TFoo.Boo: TBar;
begin
end;
{ TFoo.TBar }
procedure TFoo.TBar.Baz;
begin
end;
begin
TFoo.Create.Boo.Baz;
end.
Making a type private only means that you cannot use it (i.e. declare a variable with this type) elsewhere. Not that you cannot return it from the type its nested in.
ReplyDeleteFurther to what Stefan said; it then follows that you could access a single member of the private interface from the function return, or you could access multiple members via a with statement, but you could not declare a local variable of the private interface type.
ReplyDeleteThis is one of the reasons why we still have the "with" statement.
If the function call was expensive and you needed to access multiple members, a with statement would be the most efficient way to do it.
Stefan Glienke I know you can, I say "should not" because I don't see a good reason to do so...
ReplyDeletehow can I do a utility function for instance if I can't define a parameter of that type ?
I can understand that the class needs a private type that should not leave the unit, but once it's public throug a public function it should be public also.
Not sure what's so surprising here? All seems quite logical to me...
ReplyDeleteOh yeah ok, line 44 is inconsistent.
ReplyDeletes vanner That's not a justification for the with statement at all. The with statement could readily be removed from the language without ill effect (apart from breaking existing code).
ReplyDeleteThe way to deal with the issue that you describe is to declare a local variable and assign the result of the function call to it. Of course that won't compile with these examples because the inner type is declared as being private. But that's easily solved by designing the class correctly in the first place. If a method of one visibility uses inner types (as parameters or return value), then those types should be at least as visible as the method itself.
What a surprise - the C# compiler gives you an error when returning a private type from a public method... isn't life just boring when things are well defined and consistent?
ReplyDeleteDavid Heffernan btw, real code was a strict protected type that was used in a strict protected abstract function that child classes should override. It's a coding style for me to qualify things that are "nested declared"
ReplyDeleteFrom my pov the functions on the implementation section should be able to name the returning value using the fully qualified name, but yeah, makes it very difficult to tell without language specification.
http://docwiki.embarcadero.com/RADStudio/en/Classes_and_Objects#Strict_Visibility_Specifiers
Docs says that strict private members are visible only within the class in which there are declared, and strict protected members are visible on descendants as well
A compiler error when returning a type in function where the type's visibility is more restricted could be good
David Heffernan that depends on how much you value loose coupling.
ReplyDeleteForcing a unit into the uses clause for the sake of an unnecessary local variable creates dependancies.
Having a singleton provide objects limits the coupling to a single unit - that's about as loose as it gets in Delphi.
Admittedly, a unit of interfaces can also provide lose coupling, however interfaces don't handle all situations (e.g. records), whereas a singleton can.
That's not loosely coupling at all. You are accessing a protected member. You are not abstracting away dependencies, you are hiding it. Delegate the calls to the parent object which you are already coupled to and let it him manage the lifetime of the inner object
ReplyDeleteAgustin Ortu sorry, I didn't mention that the loose coupling example I gave was in no way related to the original post. (I thought that was obvious)
ReplyDeleteI just mentioned (in a previous post) that the same technique I use for loose coupling could also work in the case where a restricted scope would prevent the declaration of a variable.
s vanner No, that's not how to promote loose coupling. By artificially forcing you to use with. If the type is being publicly exported by its use in an exported method, that type should be exported too. C# gets this right. Delphi does not.
ReplyDeleteDavid Heffernan Oh, good grief! We use Object Pascal every day, but what about our English skills?
ReplyDeleteI in no way endorse the original poster's code. How is that? Is that clear now?
My code merely removes unit dependency as much as possible to enable maximum code reuse. It doesn't enforce it through restrictive type scoping.
Further, I am a problem solver (as all good programmers should be) so I took the challenge of finding a way of working with restrictive code. I don't support writing that sort of code, but if I was constrained to use it, I could.
Are we all happy now? Can we stop the unnecessary "moral code" posturing? We really are on the same page where our code is concerned, we just need to align our English.