Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: DragoRosso - Settembre 26, 2023, 02:38:40 pm

Titolo: FPC Corba
Inserito da: DragoRosso - Settembre 26, 2023, 02:38:40 pm
Inizio un nuovo Post per rientrare dall'OT di questo https://www.lazaruspascal.it/index.php?topic=2559.msg18995#msg18995 (https://www.lazaruspascal.it/index.php?topic=2559.msg18995#msg18995)

@Nomorelogic, ma sai che non ho compreso appieno quale sia la differenza tra l'implementazione (perchè la definzione è identica) tra CORBA e le Interface classiche (diciamo meglio quelle derivate da IInterface).

Lasciamo un attimo perdere il reference counting, dove nell'articolo indicato viene predicato il mancato rispetto del reference counting stesso anche quando questo non viene applicato (si parla dell'eventuale AV legata ad una generica esecuzione di riferimenti di Interfacce non "ìstanziate").

La differenza dove sta? Mi pare che a parte il reference counting tutto sia identico a quello che li viene indicato come "COM". L'interfaccia espone dei metodi comuni e COM definisce un metodo "universale" per conoscerle (Query).

Corba ? Da quel che viene descritto sembra sia quasi tutto a "compiled time", il che non mi sembra una grande rivoluzione ne progresso.

Ciò probabilmente è legato alla mancanza di supporto a RTL / RTTI, ma ripeto che questo sembrerebbe più un escamotage che una vera rivoluzione.

Che poi ciò si sia affermato in FPC, questo ci stà anche perchè molte altre strade non ne esistono, mantenendosi approssimativamente sulla stessa via.

Ne esco con certezze che vacillano ....
Titolo: Re:FPC Corba
Inserito da: nomorelogic - Settembre 26, 2023, 04:06:29 pm
"CORBA" è un nome che ricorda una vecchia tecnologia ma le interfacce - oggi - non si riferiscono a questa vecchia tecnologia
diciamo che è un nome preso in un momento storico ma non ha più quel significato

le interfacce CORBA in FPC non sono una rivoluzione ma sono l'implementazione di un concetto della programmazione ad oggetti già presente in altri linguaggi
come ha detto mimmo nell'altro post sono interfacce "alla-java" ma in realtà troviamo la stessa implementazione anche in altri linguaggi
fpc si è adeguato per permettere questo tipo di programmazione

rimando a questo link
https://wiki.lazarus.freepascal.org/Interfaces
dove nella sezione "Detailed introduction text" troviamo

Citazione
You should understand, that there are two kinds of interfaces. Pascal interfaces implement them both at the same time and sometimes it causes some confusion. 1) Interfaces as tool to implement multiple inheritance, as they work in some other languages, like Java 2) OLE/COM interfaces as Windows-specific language-independent way to implement OOP. So, first of all you should realize, which of this two cases is yours.

Titolo: Re:FPC Corba
Inserito da: DragoRosso - Settembre 26, 2023, 05:17:27 pm
"CORBA" è un nome che ricorda una vecchia tecnologia ma le interfacce - oggi - non si riferiscono a questa vecchia tecnologia
diciamo che è un nome preso in un momento storico ma non ha più quel significato
Questo è sempre stato chiaro e nessuno lo ha mai messo in discussione, il rimando che ho fatto riguardava solo il richiamo di memoria (non informatica, ma di cervello  :P... niente a che fare con l'abbinamento tra i due.
le interfacce CORBA in FPC non sono una rivoluzione ma sono l'implementazione di un concetto della programmazione ad oggetti già presente in altri linguaggi
come ha detto mimmo nell'altro post sono interfacce "alla-java" ma in realtà troviamo la stessa implementazione anche in altri linguaggi
fpc si è adeguato per permettere questo tipo di programmazione
rimando a questo link
https://wiki.lazarus.freepascal.org/Interfaces
dove nella sezione "Detailed introduction text" troviamo
Citazione
You should understand, that there are two kinds of interfaces. Pascal interfaces implement them both at the same time and sometimes it causes some confusion. 1) Interfaces as tool to implement multiple inheritance, as they work in some other languages, like Java 2) OLE/COM interfaces as Windows-specific language-independent way to implement OOP. So, first of all you should realize, which of this two cases is yours.
Non esiste alcuna spiegazione sulla differenza, la definizione è la stessa. Non viene in alcun modo spiegato quale è la differenza di implementazione, se non tra le righe capendo che come ho riferito sia fatto quasi tutto "magicamente" a compiler time. Dire che è tipo Java non vuole dire nulla. Tutte le Interfacce sono comuni in tutti i linguaggi compreso Delphi, FPC, etc...
E dire che è COM compatibile vuole dire solo che ha un metodo predefinito, cioè la "QueryInterface" tramite cui viene ritornato il "puntatore al metodo". Non sò neanche se sono obbligatorie le "_AddRef" e "_ReleaseRef".

Quindi, ancora non capisco la differenza, se non che FPC ha il supporto solo a compiled time (praticamente) e non a run time ...

Tra l'altro, giusto per terminare in bellezza, le implementazioni che ho trovato in FPC (nei sorgenti di FPC e Lazarus) hanno tutte come riferimento la chiamata a QueryInterface per la verifica dell'interfaccia (il famoso Supports(....) ).

Poi magari mi sbaglio, anzi sicuramente mi sbaglio, ma non mi pare ci sia alcuna differenza tra COM e non COM, anzi ....

Ciao
Titolo: Re:FPC Corba
Inserito da: Mimmo - Settembre 26, 2023, 06:31:47 pm
Magari a livello implementativo le differenze sono minime, qualche if qua e la :-)
A livello logico le differenze però ci sono. L'interfaccia "corba" di fpc è l'interfaccia "normale", nessun free automatico, nessun guid, nessun metodo AddRef da compilare. E' l'escamotage che, java prima (da qui "alla-java") e c# dopo, si sono inventati per supportare l'ereditarietà multipla in oop.
Senza fare guerre di religione, io penso che se uno ha bisogno delle interfacce oop possa allegramente e felicemente utilizzare l'implementazione data da fpc con l'opzione infelicemente chiamata corba perchè con quella puoi scrivere del codice più semplice e leggibile. Poi liberi tutti, ad esempio per mantenere la compatibilità con Delphi, di lavorare con le interfacce ole/com.
Io ricordo che anche taroccando il contatore qualche problema lo avevamo avuto col nostro ipercubo però non ricordo i dettagli.. se trovo il tempo magari faccio una verifica.



Titolo: Re:FPC Corba
Inserito da: DragoRosso - Settembre 26, 2023, 07:57:10 pm
Magari a livello implementativo le differenze sono minime, qualche if qua e la :-)
A livello logico le differenze però ci sono. L'interfaccia "corba" di fpc è l'interfaccia "normale", nessun free automatico, nessun guid, nessun metodo AddRef da compilare. E' l'escamotage che, java prima (da qui "alla-java") e c# dopo, si sono inventati per supportare l'ereditarietà multipla in oop.
Senza fare guerre di religione, io penso che se uno ha bisogno delle interfacce oop possa allegramente e felicemente utilizzare l'implementazione data da fpc con l'opzione infelicemente chiamata corba perchè con quella puoi scrivere del codice più semplice e leggibile. Poi liberi tutti, ad esempio per mantenere la compatibilità con Delphi, di lavorare con le interfacce ole/com.
Io ricordo che anche taroccando il contatore qualche problema lo avevamo avuto col nostro ipercubo però non ricordo i dettagli.. se trovo il tempo magari faccio una verifica.
Guarda che Delphi supporta la definizione di interfaccia senza GUID :o

E  serve la QueryInterface (e quindi le GUID) se si hanno interfacce multiple derivate nella classe istanziata.
Inoltre la GUID lo dichiari, come ho indicato se devi a runtime effettuare delle operazioni "virtuali" come IS, AS, Supports, ... e quindi anche le QueryInterface deve esserci.

E se nei casi indicati la GUID serve e anche la "QueryInterface" non vedo ripeto alcuna differenza.

Quindi non vedo alcuna differenza. E le interfacce "multiple" sono una caratteristica tipica della OOP, e servono proprio a consentire di fatto l'ereditarietà multipla (come ho già accennato, non è proprio così ma ci si avvicina) che non è consentita attraverso le sole Classi. Penso che esista da sempre.
E per implementarle, fino a prova contraria che vorrei capire, deve esserci la GUID e la QueryInterface.

La mia non è una polemica, vorrei solo capire se effettivamente c'è una strada diversa come dite, ma non riesco a comprenderla. Secondo me parliamo della stessa cosa.

Poi non sono andato nei meandri del codice sorgente ne in FPC ne in Delphi per vedere se a livello assembler fanno qualcosa o magicamente il compilatore si inventa il coniglio nel cappello ... ma non mi interessa questo.

Secondo me la cosa interessante è: si può fare quello sotto scritto senza GUID, senza QueryInterface, senza Addref, senza ReleaseRef ?
Sia in Delphi che in Lazarus ? E con cosa obbligatorio ?
Devo modificare qualcosa per avvicinarci a quello che ho scritto ? Devo cambiare nomi di metodi ? Devo aggiungere qualcosa alle procedure ?

Se no parliamo di aria fritta.

Sono le prove che farò a livello base, cercando di non usare funzioni "speciali",  di cui però mi aspetto già le risposte.

Esempio scritto così come me lo immagino (lasciamo perdere se è utile o no):
Codice: [Seleziona]
type
  IStampaLaser = interface
    procedure Stampa;
  end;

  IStampaInkjet = interface
    procedure Stampa;
  end;

  TProvadiStampa = Class(TObject, IStampaLaser, IStampaInkJet)
     public
         procedure Stampa;
   end;

Implementation

procedure TProvadiStampa.Stampa;
begin
   ShowMessage('Sto stampando con che interfaccia ????');
end;
Appena ho testato posto qui i risultati. Serve anche a me per capire se ci sono altre strade (quella pura Pascal come dite), perchè sino ad ora ho usato la strada classica (quella che viene definita COM) e mi farebbe piacere se ci fosse un altro modo ...

Ciao
Titolo: Re:FPC Corba
Inserito da: DragoRosso - Settembre 27, 2023, 12:00:32 pm
Ho testato le interfacce con diversi metodi (uguali, diversi, con parametri, in overload) e diverse classi sia con {$Intrefaces corba} sia normali. Con GUID e senza GUID, con interfacce multiple o singole. Il tutto in x64.

Il comportamento è identico sia in Delphi che in Lazarus. Mi aspettavo una cosa simile, anche se sono rammaricato perchè speravo ci fosse qualcosa di nuovo.

Cosa cambia tra i due ambienti:

1) RTL / RTTI, con Delphi si riescono ad ottenere più informazioni. Ma è sicuramente la mia scarsa conoscenza delle RTL / RTTI di FPC che influisce.

2) Debugging: in Lazarus non sono riuscito a trovare alcun modo per debuggare le "interfacce".

3) Quando si usa lo "switch corba", le Interfacce, che anche se sono di tipo "interface" normalmente venivano identificate con la GUID e si "potevano passare come parametro", rimangono di tipo "interface" ma senza possibilità di essere passate come parametro anche se hanno la GUID (anche qui probabilmente una mia lacuna).
Ciò non cambia praticamente nulla (almeno normalmente) per quello che riguarda il funzionamento.

Tutti i metodi QueryInterface, _AddeRef e _ReleaseRef sono sempre implementati, e l'incremento o il decremento sono effettuati in maniera "aotmica" quindi tendenzialmente è ThreadSafe.

Con lo "switch corba" il compilatore "elimina" le chiamate ad _AddRef e _ReleaseRef (in quest'ultima verrebbe effettuata la "distruzione" del riferimento).

Tutto il resto rimane immutato. Ho provato a fare dei test in termini di operazioni e analisi delle tempistiche di esecuzione ed è necessario effettuare 1 MILIONE di operazioni sulla interfaccia per avere meno di 1 MILLISECONDO di differenza complessivi tra "corba" e "non corba", quindi non ritengo che nelle operazioni comuni ciò sia impattante.

Spulciando i sorgenti FPC non mi pare si usi "corba" ...

Ciao
Titolo: Re:FPC Corba
Inserito da: nomorelogic - Settembre 27, 2023, 12:34:28 pm
la differenza è puramente di concetto:
le interfacce COM includono ereditarietà multipla + reference counting, le interfacce "normali" (che fpc chiama corba) solo ereditarietà multipla

mentre l'ereditarietà multipla è un concetto OOP di design e non ha nessun effetto a runtime, il reference counting non è propriamente un concetto ma ha invece effetto a runtime in quanto cambia lo stato della macchina (liberando automaticamente le risorse)

a livello teorico si tratta di 2 comportamenti eterogenei impacchettati insieme quando - i teorizzatori dell'OOP sostengono -  non dovrebbero esserlo (e questa credo sia una teorizzazione corretta)

da quì la volontà di implementare le interfacce solo come concetto OOP di ereditarietà multipla eliminando il reference counting
(il GUI è presente nelle 2 implementazioni in quanto fa parte del concetto di ereditarietà multipla)

quindi - nel campo dell'ereditarietà - non c'è alcuna differenza tra le 2 implementazioni
col debugger infatti puoi solo vedere come funziona il reference counting quando usi le COM (RTL/RTTI non fanno testo se non quando usano questo meccanismo)

nomorelogic
Titolo: Re:FPC Corba
Inserito da: DragoRosso - Settembre 27, 2023, 02:31:53 pm
Ti dò ragione concettuale, ma non pratica   :P

Il reference counting (o meglio l'effetto del) può essere annullato effettuando l'override delle due funzione e ponendole a -1 costante.

Il fatto che ci sia il compilatore che magicamente fà sparire la chiamata mi pare una "cavolata". Se doveva essere fatto ci doveva essere una implementazione senza i metodi .. tra l'altro le interfacce consentono proprio di implementare solo i metodi necessari, e non una valanga di roba che non serve a nulla (eredita da classi antiche).

Il compilatore dovrebbe ottimizzare, mica immischiarsi a togliere metodi (se non per pura ottimizzazione) ....

Comunque l'importante è combinare come si dice. Ora mi è chiara la cosa, prima era vaga e mi rodeva ...

Alla prossima, CIAOOO  :D :D :D
Titolo: Re:FPC Corba
Inserito da: nomorelogic - Settembre 27, 2023, 05:57:06 pm
visto che ci siamo ho cercato di studiare un po' di più la cosa e mi sono chiesto il perché della rimozione di  _AddRef e _ReleaseRef

la risposta, dopo molto girovagare l'ho trovata nell'unico posto dove doveva essere: nella documentazione ufficiale :)
https://www.freepascal.org/docs-html/prog/progsu37.html#x44-430001.2.37

in pratica le interfacce COM differiscono dalle CORBA anche per l'attribuzione del parent
nel caso di COM il parent delle interfacce è IUnknown (tramite TInterfacedObject che deve essere nella dichiarazione della classe, che si occupa del reference counting)
nel caso CORBA, il parent non è necessario ma, per mantenere la compatibilità tra il cambio di direttive, è possibile usare comunque TInterfacedObject come parent della classe finale (ma le chiamate ad _AddRef e _ReleaseRef verranno eliminate)

chiaramente ho fatto qualche prova
usando le interfacce CORBA, la dichiarazione "TMyClass1 = class (IInterfacciaCORBA)" è valida
Codice: [Seleziona]
unit Unit1;

{$mode ObjFPC}{$H+}
{$interfaces corba}

interface

uses
  Classes, SysUtils;


type
  IInterfacciaCORBA = interface
    procedure DoThis (value: integer);
  end;

  { TMyClass1 }

  TMyClass1 = class (IInterfacciaCORBA)
     procedure DoThis (value: integer);
   end;

implementation

{ TMyClass1 }

procedure TMyClass1.DoThis(value: integer);
begin

end;

end.

usando invece le interfacce COM, sono costretto a dichiarare la classe come "TMyClass2 = class (TInterfacedObject, IInterfacciaCOM) "
eliminando "TInterfacedObject" dalla dichiarazione si otterrà l'errore di compilazione:
unit2.pas(17,15) Error: No matching implementation for interface method "QueryInterface(constref TGuid;out <Formal type>):System.LongInt; CDecl;" found

Codice: [Seleziona]
unit Unit2;

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils;

type
  IInterfacciaCOM = interface
    procedure DoThis (value: integer);
  end;

  { TMyClass2 }

  TMyClass2 = class (TInterfacedObject, IInterfacciaCOM)
     procedure DoThis (value: integer);
   end;

implementation

{ TMyClass2 }

procedure TMyClass2.DoThis(value: integer);
begin

end;

end.


Edit:
ho visto che anche il GUID nelle CORBA è facoltativo
in quel caso spetta al programmatore evitare conflitti nel nominare le interfacce

Edit 2:
ora che è chiarito l'arcano della rimozione dei metodi _AddRef e _ReleaseRef
ha anche più senso l'implementazione delle interfacce come semplice concetto di ereditarietà multipla:
usando CORBA ed evitando TInterfacedObject si usa in modo pulito l'ereditarietà ma si può sempre ricorrere alla compatibilità se necessario
chapeau :)


nomorelogic
Titolo: Re:FPC Corba
Inserito da: DragoRosso - Settembre 27, 2023, 07:07:09 pm
Ti sbagli, i metodi ci sono ancora, prova a vedere e la classe TMy_Class possiede _Addref e tutto il resto ...
Una classe, anche se non la specifichi, deriva comunque da TObject che ha quei metodi.

Ciao
Titolo: Re:FPC Corba
Inserito da: nomorelogic - Settembre 27, 2023, 07:27:15 pm
come fanno ad esserci se sono in TInterfacedObject?  :o

Edit:
scusa puoi dirmi dove verifichi la presenza di _Addref?
Col debugger mi sa che non trovo il modo di fare l'inspect...
Titolo: Re:FPC Corba
Inserito da: nomorelogic - Settembre 27, 2023, 08:00:37 pm
sono riuscito a controllare con l'object inspector
la pratica a me combacia con la teoria: con le interfacce CORBA i metodi _AddRef e compagnia non ci sono  :)


Titolo: Re:FPC Corba
Inserito da: nomorelogic - Settembre 27, 2023, 08:04:14 pm
Una classe, anche se non la specifichi, deriva comunque da TObject che ha quei metodi.

_AddRef & soci non sono in TObject...
Forse stai verificando su Delphi?
Titolo: Re:FPC Corba
Inserito da: DragoRosso - Settembre 27, 2023, 08:07:07 pm
sono riuscito a controllare con l'object inspector
la pratica a me combacia con la teoria: con le interfacce CORBA i metodi _AddRef e compagnia non ci sono  :)

Io no, a me Object Inspector non funziona con le interfacce, ne le watch.

_AddRef & soci non sono in TObject...
Forse stai verificando su Delphi?

In mancanza di meglio faccio dal codice ....  :o
Titolo: Re:FPC Corba
Inserito da: DragoRosso - Settembre 27, 2023, 08:10:36 pm
Spe' .... c'è una IInterface rimasta nelle dichiarazioni dei metodi ... forse è quello ....



EDIT: NO, RIMANGO LO STESSO ....
Titolo: Re:FPC Corba
Inserito da: nomorelogic - Settembre 27, 2023, 08:12:44 pm
per object inspector devi fare "analizza" sulla classe e, poi, quando si apre la finestra, clicca bottone "evaluate"
Titolo: Re:FPC Corba
Inserito da: nomorelogic - Settembre 27, 2023, 08:18:09 pm
Spe' .... c'è una IInterface rimasta nelle dichiarazioni dei metodi ... forse è quello ....



EDIT: NO, RIMANGO LO STESSO ....

che versione di lazarus / fpc?
Titolo: Re:FPC Corba
Inserito da: DragoRosso - Settembre 27, 2023, 09:01:26 pm
che versione di lazarus / fpc?
Versione 2.2.6 stabile, FPC distribuito stabile.

EDIT: Anche istanziando la classe la variabile non viene vista con Object Inspector, dice che TObject ha un errore all'offset $3 (var qualcosa ...)

E' possibile che FPC o Lazarus si sia sporcato, tra aggiungi e togli librerie di terze parti.

Comunque sia che ci siano o non ci siano le _AddRef & company è sicuro che non vengono chiamate e quindi il reference counting non c'è.

Se con "corba attivo" uso "TInterfacedObject" il reference counting rimane disattivo ovviamente perchè nonostante la presenza di _AddRef nella classe, le interfacce non gli hanno quei metodi, secondo a quanto a te risulta con il debug e quindi nessuno può chiamarli ....

Se inserisco nella dichiarazione delle interfacce "interface(IInterface)" riprende l'uso del reference counting anche se "corba è attivo".

Quindi come dici tu deve essere che viene modificata la definizione di interface, e con corba attivo interface non deriva da nulla e quindi che ci siano o meno i metodi nella classe non importa in alcun modo, tanto l'interface base non ha alcun metodo definito (a meno che non di derivi a mano).

Non è quindi una "magia" del compilatore, ma il cambio di definizione di "interface".

Ciao