Private Interface Members don't work

Hi there,

the example code from docs.elementcompiler.com regarding “Private Interface Members” in Qxygene does not seem to work.

(E425) Element is not allowed in an interface type

My apologies for this. i’ll need to see whether the docs are wrong or the compiler; for now, visibility sections don’t work, but visibility modifiers after the methid do:

type
  ILogger = public soft interface
    method Log(aInfo: String);
    
    method Log(aFormat: String; params aParameters: array of Object);
    begin
      Log(CustomFormat(aFormat, aParameters));
    end;
    
    method CustomFormat(aFormat: String; params aParameters: array of Object): String; private;
    begin
      //...
    end;

  end;

Logged as bugs://E25782.

Sorry to say this - if i add visibility modifiers as recommended, it compiles but still doesn’t work.

image

“Foo” in this testcase is private, but appears in CC and is callable.

namespace ConsoleApplication1;

type
  ITest = public interface
    method Foo; private;
    method Bar;
  end;

  TestObject = public class(ITest)
  private
    method Foo; 
    begin
      writeLn('Hmm...');
    end;
  public
    method Bar;
    begin
      writeLn('Hello');
    end;
  end;

  Program = class
  public

    class method Main(args: array of String): Int32;
    begin
      var o: ITest := new TestObject;
      o.

      readLn;
    end;

  end;

end.

Separate bug; logging.

1 Like

Logged as bugs://E25783.

Note that the fix for this will be that it doesn’t compile. It doesn’t really make sense to have an interface method (that another class is required to implement) that’s private. How would you implement it ?

I only tried to use a feature that is is described in the documentation. :wink:

But indeed - interfaces with private members MAY be useless. I struggeled over this, because i tried to hide some wired compiler-generated stuff around property getters. Maybe there is another problem there and i tried to fix the problem from the wrong end.

(There seems to be an issue with interface property getters and setters and some auto-generated extension class with mappings in it. But I can’t understand that exactly at the moment and still have to play with it first.)

Btw: code completion inserts a private method (section! AND method-wise) if you let it generate an getter method…

  ITest = public interface
  private
    method GetSomeProp: Integer; private;
    begin
    end;
    property SomeProp: Integer read GetSomeProp
  end;

the idea of the feature was originally to hide the methods that do have an implementation (to be called from other methods in the same interface). Obviously it shouldn’t do that for “real” interface methods. We’ll fix the methods. (Also the CC completion is wrong)

I think, i found the reason, which caused me to fiddle around with this “private-interface-stuff”:

Delegating the Implementation of an Entire Interface reveals hidden compiler generated methods and makes them accessible for the caller.

namespace ConsoleApplication42;

type
  ITest = public interface
    property Foo: Integer read;
  end;

  TestImplementer = public class(ITest)
  public
    property Foo: Integer read 42;
  end;

  TestOMat = public class(ITest)
  private
    fTest := new TestImplementer; implements public ITest;
  public
  end;

  Program = class
  public

    class method Main(args: array of String): Int32;
    begin
      var tom := new TestOMat;
      writeLn(tom.get_Foo);  // <-- Visible to cc and callable here. Shouldn't be there.

      var ti := new TestImplementer;
      writeLn(ti.get_Foo);  // <--. Invisble to cc but nevertheless callable here. 
            
      readLn;
    end;

  end;

end.

One can say, it is an cosmetic issue, but i have an interface with a handful of properties and have wondered where all the “get_”-methods came from.

Logged as bugs://E25786.

Can you tell me why you added the public in there?

    fTest := new TestImplementer; implements public ITest;

Without public it would be private; but I would like to know why you did it this way.

bugs://E25786 was closed as no change required.

If I omit the “public” then the implemented interface is not accessible from the outside without a cast. Not even if I move the implementing object to the “public” area.
(Which I didn’t want, because the “implementer” shouldn’t necessarily be directly visible.)

But since “TestOMat” is defined to implement ITest, it should work without cast, IMO.

namespace ConsoleApplication42;

type
  ITest = public interface
    property Foo: Integer read;
  end;

  TestImplementer = public class(ITest)
  public
    property Foo: Integer read 42;
  end;

  TestOMat = public class(ITest)
  private
  public
    fTest := new TestImplementer; implements ITest;
  end;

  Program = class
  public

    class method Main(args: array of String): Int32;
    begin
      var tom := new TestOMat;
      writeLn(tom.Foo);   // <-- (E44) No member "Foo" on type "TestOMat"		
            
      readLn;
    end;

  end;

end.

Yeah that’s what I was going for. public will do exactly what you want. I do think get_* probably shouldn’t be visible (but it should be callable).

1 Like

bugs://E25782 was closed as fixed.

bugs://E25783 was closed as fixed.

Yes. with “public:” the interface members become public on the class type; without, they are only available via cast to the interface. That’s the entire point of using “public” there — IOW this seems to be working exactly as it should.