Italian community of Lazarus and Free Pascal

Programmazione => Componenti Aggiuntivi => Topic aperto da: DragoRosso - Aprile 16, 2021, 11:10:38 am

Titolo: [RISOLTO] Porting componenti fatti x Delphi
Inserito da: DragoRosso - Aprile 16, 2021, 11:10:38 am
Salve, come nuovo utente di Lazarus stò passando pian piano i progetti sviluppati con il più celebre "antagonista" appunto in FPC / Lazarus.

Prime "cose" da passare sono ovviamente tutte le utility e gli add-on che un progetto normalmente usa e che non fanno parte dell'ambiente integrato.

Alcuni pacchetti sono fortunatamente compatibili, tipo JVC e parte di JCL, altri invece no sopratutto quelli un pò più vecchietti.

In questo momento stò portando un pacchetto per la gestione delle seriali di comunicazione (uno dei tanti TComPort) ed effettivamente ho riscontrato delle difficoltà (già superate, il primo progetto è già in Lazarus e funziona alla grande) che mi hanno fatto un pò riflettere.

Inanzitutto sono diventato matto all'inizio perchè mi venivano segnalati degli errori riguardanti delle semplici chiamate a funzioni che risultavano dichiarate in modo impeccabile e che invece fpc mi "segnalava" come incorrette.

Esplorando un pò più a fondo, ho scoperto che a fpc non piace, e su questo gli dò assolutamente e piena ragione, che variabili locali o parametri di una funzione siano chiamate come nomi di proprietà definite nella classe (anche se definite diversamente).

Ovviamente a Delphi non fà ne caldo ne freddo, va bene tutto (mi pare di tornare al vecchio Basic dove potevi assegnare una stringa a una variabile numerica  :'( ).

Fermo restando che non mi sarebbe mai passato per la testa di fare qualcosa di simile, ossia usare come nome di variabile il nome di una proprietà, secondo le regole standardizzate del PASCAL è possibile usare nomi di variabili identiche a nomi di proprietà (sempre all'interno della stessa classe ovviamente) ?

Si sà che variabili globali vengono nascoste da variabili locali con lo stesso nome.

E' solo uno sfizio "per sapere", già per mio modo di fare neanche le variabili locali hanno mai un nome uguale a qualsiasi altra variabile globale o definite in una classe, anche perchè le minime regole di definizione delle variabili già impediscono che questo accada (Volume, fVolume,  lVolume, gVolume, etc ...).

P.S.: sò che c'è il pacchetto LazSerial per la gestione delle seriali, ma il componente che uso mi pare sia un pò più completo.

Un saluto a tutti
 
Titolo: Re:Porting componenti fatti x Delphi
Inserito da: nomorelogic - Aprile 16, 2021, 12:46:14 pm
con questo problema del nome delle variabili e dei parametri mi ci sono imbattuto anche io all'inizio e non capivo il motivo

poi l'illuminazione: il compilatore fpc ha diversi modi di compilare il pascal
il "delphi mode" attiva la compilazione, appunto, in modalità Delphi

se leggi in questo link, al punto 8
https://www.freepascal.org/docs-html/prog/progse74.html
vedrai che dovrebbe risolvere il tuo problema in quanto dovrebbe accettare che i parametri dei metodi di una classe, abbiano lo stesso nome delle proprietà

comunque bisogna ammettere che leggere il seguente codice:
Codice: [Seleziona]
procedure TClasseAAA.ImpostaTemp(Temperatura: double);
begin
  ...
  Temperatura := Temperatura;
  ...
end;

è ambiguo e la domanda potrebbe sorgere spontanea: assegno la proprietà dell'istanza o assegno il parametro?  :o
mentre il seguente non lascia spazio a fraintendimenti di lettura:

Codice: [Seleziona]
procedure TClasseAAA.ImpostaTemp(ATemperatura: double);
begin
  ...
  Temperatura := ATemperatura;
  ...
end;

Diciamo che la "A" come prefisso del nome del parametro del metodo, la puoi intendere come l'articolo indeterminativo "un" - :) -, per cui il tutto è molto più chiaro.


visto che ci siamo
a proposito delle dichiarazioni di metodi, funzioni e procedure:
a meno che non sia espressamente richiesto dal contesto, tutti i parametri dovrebbero essere const
(sopra non l'ho messo perché sennò non ci sarebbe stata l'ambiguità  ;D )

Titolo: Re:Porting componenti fatti x Delphi
Inserito da: DragoRosso - Aprile 16, 2021, 02:39:02 pm
No, no, non ci sono problemi, anzi ho rivisto la classe TComPort e l'ho rimessa parzialmente a posto.
Non esiste proprio utilizzare nomi uguali per tutto.

MA IL DUBBIO NON E' STATO DIRIMATO ... SI POTREBBE FARE ? O è una libertà di Delphi ?

Dei vari modificatori mi sono documentato (aprendo un codice Lazarus è il primo define nuovo che leggi  :D ), però il fatto di usarlo come Delphi non se ne parla sarebbe un pò riduttivo, se Delphi permette questo.

L'unica cosa che secondo me si dovrebbe mettere a posto (a meno che non si possa già fare e sbagli io) è l'assegnazione degli eventi:
- creo un evento OnClick, e assegno questo evento a runtime a tutta una serie di componenti. Adesso come adesso con modalità "{$Mode objFPC}" devo assegnare all'evento il puntatore alla procedura. Questo però induce una possibile problematica (a parte l'odio di lavorare con i puntatori), ossia la procedura potrebbe non essere compatibile con quanto richiesto dall'evento e non viene controllato in fase di compilazione dando adito a possibili problematiche difficili poi da diagnosticare a runtime.

esempio:

Codice: [Seleziona]
//Procedura generica
procedure TForm1.JvLED1Click(Sender: TObject);
begin
  if Sender is TJvLed then
    (Sender as TJvLed).Status := not (Sender as TJvLed).Status;
end;

//Assegnazione attuale (senza controllo)
Led2.OnClick := @JvLED1Click;

//Assegnazione preferibile (con controllo, ma genera l'errore (Error: Wrong number of parameters specified for call to "JvLED1Click")
Led2.OnClick := JvLED1Click;

Saluti
Titolo: Re:Porting componenti fatti x Delphi
Inserito da: Stilgar - Aprile 16, 2021, 03:47:47 pm
Ciao.


Delphi nasconde la natura della callback.


Ma di fatto è un puntatore a metodo o procedura/funzione. Dipende da come è dichiarato il prototipo di chiamata.


Sul fatto che possa dare errore, mi sembra di ricordare, che controlla. Essendo un puntatore tipizzato ti castiga se passi un OnKeyUp al posto di un OnChange. Ma vado a memoria, potrei ricordarmi male.


Se poi fai un cast passando per puntatore generico, saresti solo masochista nel farlo :)


Che poi stia sulle scatole è una questione di gusti e quelli non si discutono.
Codice: [Seleziona]
{*
Led2.OnClick := JvLED1Click;
*}

[/size]Qui stai tentando di invocare il metodo e assegnare ad OnClick il risultato della chiamata. Il compilatore ti sta gentilmente chiedendo di passare un parametro in chiamata. Se mettessi un nil come parametro, mi aspetto che ti dica che la procedura non restituisce nulla nello stack.




Stilgar
Titolo: Re:Porting componenti fatti x Delphi
Inserito da: nomorelogic - Aprile 16, 2021, 03:54:58 pm
Mentre stavo scrivendo ha risposto Stilgar, ma la risposta la metto comunque (oramai l'ho scritta :D )





MA IL DUBBIO NON E' STATO DIRIMATO ... SI POTREBBE FARE ? O è una libertà di Delphi ?

forse non ho capito la domanda
il fatto è che il compilatore Delphi accetta quella sintassi (e di conseguenza la sua semantica)

fpc invece no, non ha quella sintassi (e secondo me è più corretto l'approccio di fpc)
però, vista la mole di codice Delphi a disposizione, hanno inventato la modalità Delphi di modo da poter compilare quel codice anche in progetti fpc
la modalità delphi, per concludere, la vedo utile solamente per fare il porting senza voler riscrivere con la sintassi di fpc

si tratta alla fine di una scelta del programmatore


L'unica cosa che secondo me si dovrebbe mettere a posto (a meno che non si possa già fare e sbagli io) è l'assegnazione degli eventi:
- creo un evento OnClick, e assegno questo evento a runtime a tutta una serie di componenti. Adesso come adesso con modalità "{$Mode objFPC}" devo assegnare all'evento il puntatore alla procedura. Questo però induce una possibile problematica (a parte l'odio di lavorare con i puntatori), ossia la procedura potrebbe non essere compatibile con quanto richiesto dall'evento e non viene controllato in fase di compilazione dando adito a possibili problematiche difficili poi da diagnosticare a runtime.

Beh, essendo l'evento un puntatore ad una procedura ho paura che non ci siano alternative.
Proprio per evitare i problemi di compilazione, molti metodi destinati ad essere assegnati come risposta ad un evento si aspettano un unico parametro Sender (vedi dichiarazione di TNotifyEvent).

Quindi l'assegnazione seguente
Codice: [Seleziona]
Led2.OnClick := @JvLED1Click;
E' corretta perché assegna all'evento OnClick l'indirizzo del metodo "JvLED1Click".


L'assegnazione sotto è errata per diversi motivi:
Codice: [Seleziona]
Led2.OnClick := JvLED1Click;


nomorelogic
Titolo: Re:Porting componenti fatti x Delphi
Inserito da: Stilgar - Aprile 16, 2021, 03:58:36 pm
La modalità Delphi la torvo più comoda con i template/generics




Dover creare inner class come se piovesse, non mi è molto simpatica.


Pensa alle Liste Generiche. L'iteratore è ridefinito dentro al generics.


Con la modalità delphi puoi avere 2 contenitori generici e definire 1 solo iteratore.


(Ripeto, stiamo parlando di gusti)




Stilgar
Titolo: Re:Porting componenti fatti x Delphi
Inserito da: DragoRosso - Aprile 16, 2021, 04:26:33 pm
@Stilgar, @Nomorelogic

".Onclick" --- Non è un metodo ma una proprietà. Il metodo eventualmente sarebbe ".Click"

Scrivendo Led2.Onclick := .......      io non eseguo metodi, ma assegno qualcosa a una proprietà (poi cosa ci sia dietro, giustamente mi potrebbe essere "nascosto").

Per ciò che riguarda il puntatore, confermo che effettivamente c'è un controllo sul puntatore stesso quindi il problema è solo di estetica e di gusto.

Sull'argomento sintassi  e Delphi rimango d'accordo parzialmente:

1) Generics, containers, etc .... possono andare bene se non violano le regole basilari. Ovvio che nel pensiero di riscrivere tutto il codice, ci può stare che un occhio lo si chiuda.

2) Invece sul consentire l'assegnazione di nomi identici in "tutte le parti", quello non mi prende tanto. Si dà adito veramente a tanti possibili problemi in fase di runtime (io non l'ho mai fatto, tant'è vero che lo scopro adesso che FPC nativamente lo nega su componenti importati :) ).

Quello che mi piace, oltre al linguaggio PASCAL vero e proprio, e che praticamente a RUNTIME i problemi sono veramente ZERO o quasi, se si sfruttano le caratteristiche del linguaggio e non si usano scorciatoie.

Il debugger io lo uso più che altro per capire i "percorsi" legati alle chiamate, uso della memoria e simili e quindi ad ottimizzare il codice, piuttosto che per debuggare l'applicazione alla ricerca di BUG.

Ciao.


Titolo: Re:Porting componenti fatti x Delphi
Inserito da: Stilgar - Aprile 16, 2021, 04:39:28 pm
Sì, d'accordo OnClick è una property. Forse mi sono spiegato male.

Se togli @ nell'assegnazione, cosa capisce il compilatore?
Che vuoi invocare il metodo, non estrarne il puntatore. Quindi ti avvisa che hai dimenticato il parametro per invocare il metodo. Poi scazzerebbe lo stesso, visto che è una procedure al posto di una function.

Qui sto parlando di fpc.

Stilgar
Titolo: Re:Porting componenti fatti x Delphi
Inserito da: DragoRosso - Aprile 16, 2021, 04:50:50 pm
@Stilgar
Effettivamente spiegato così mi ha un attimo aperto gli occhi. La scrittura che avevo proposto poteva essere (anzi è da FPC)  interpretata come dici tu (che tra l'altro è l'unico modo corretto di interpretazione).

Stò scoprendo che fino ad ora ho fatto un mucchio di schifezze (in realtà non tantissime però) dal punto di vista logico / semantico, e quel che mi rode di più e che mi veniva concesso di farle (anche se il risultato era quello voluto da me) !!!

Grazie per la discussione, non si finisce mai di imparare.

Sono sempre più convinto nel passare in toto a Lazarus.

Saluti
Titolo: Re:Porting componenti fatti x Delphi
Inserito da: DragoRosso - Aprile 17, 2021, 12:28:51 am
Qui spiegano tutto.
https://www.freepascal.org/docs-html/user/usersu86.html#x130-1370007.3.1 (https://www.freepascal.org/docs-html/user/usersu86.html#x130-1370007.3.1)

Citazione
Note that the -Mobjfpc mode switch is to a large degree Delphi compatible, but is more strict than Delphi. The most notable differences are:

1.
    Parameters or local variables of methods cannot have the same names as properties of the class in which they are implemented.
2.
    The address operator is needed when assigning procedural variables (or event handlers).
3.
    AnsiStrings are not switched on by default.
4.
    Hi/Lo functions in Delphi are always evaluated using a word argument, in FPC there are several overloaded versions of these functions, and therefor the actual type of the passed variable is used to determine which overload is called. This may result in different results.

E direi che più rigore và benissimo.