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

Comments

  1. Reproduced on Delphi 2010, 10 Seattle and 10.1 Berlin

    ReplyDelete
  2. Seems 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.

    It 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.

    ReplyDelete
  3. 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.

    ReplyDelete
  4. I 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.

    BTW the public function GetPrivate and GetProtected should not compile for the same reason.

    ReplyDelete
  5. Paul TOTH Wrong, you can:

    program 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.

    ReplyDelete
  6. 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.

    ReplyDelete
  7. Further 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.

    This 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.

    ReplyDelete
  8. Stefan Glienke I know you can, I say "should not" because I don't see a good reason to do so...

    how 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.

    ReplyDelete
  9. Not sure what's so surprising here? All seems quite logical to me...

    ReplyDelete
  10. s 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).

    The 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.

    ReplyDelete
  11. 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?

    ReplyDelete
  12. David 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"

    From 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

    ReplyDelete
  13. David Heffernan that depends on how much you value loose coupling.
    Forcing 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.

    ReplyDelete
  14. 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

    ReplyDelete
  15. Agustin 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)

    I 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.

    ReplyDelete
  16. 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.

    ReplyDelete
  17. David Heffernan Oh, good grief! We use Object Pascal every day, but what about our English skills?

    I 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.

    ReplyDelete

Post a Comment