Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: DragoRosso - Novembre 22, 2024, 11:44:36 pm

Titolo: Sintassi pascal
Inserito da: DragoRosso - Novembre 22, 2024, 11:44:36 pm
Ciao a tutti.

faccio una domanda che sarà magari stupida ma è curioso il comportamento:
- per quale motivo queste due "scritture" differiscono ?

In particolare, perchè la prima non genera errore ?

Codice: [Seleziona]
//Questa forma è valida, anche se nella prima riga dopo il "type" TProvaRec non è stato ancora dichiarato e quindi dovrebbe
//essere formalmente un errore.

type
  PProvaRec = ^TProvaRec;

  TProvaRec = packed record
    RefCnt: Integer;
    Length: NativeInt;
  end;

Codice: [Seleziona]
//Questa invece và giustamente in errore, ma sintaticamente dovrebbe essere identica a quella precedente ... invece evidentemente non lo è
//In ogni caso mi aspettavo che anche la forma precedente andasse in errore

type
  PProvaRec = ^TProvaRec;

type
  TProvaRec = packed record
    RefCnt: Integer;
    Length: NativeInt;
  end;

Titolo: Re:Sintassi pascal
Inserito da: bonmario - Novembre 23, 2024, 07:20:11 am
Scusa, l'ho riguardato più volte, ma sembra lo stesso codice duplicato ... non vedo la differenza tra i 2 !!!

Ciao, Mario
Titolo: Re:Sintassi pascal
Inserito da: DragoRosso - Novembre 23, 2024, 08:21:47 am
Scusa, l'ho riguardato più volte, ma sembra lo stesso codice duplicato ... non vedo la differenza tra i 2 !!!
La differenza è che mentre nel primo c'è un solo "type" nel secondo ce ne sono due.

E nel secondo il compilatore si comporta come mi aspetto (cioè genera errore), mentre nel primo non dà errori.

Anche su Delphi è così, quindi ritengo che ovviamente sia giusto così.
Volevo sapere il perchè (evidentemente ha a che fare con i construtti del linguaggio).

Da una nota relativa alla definizione del Pascal:
Citazione
The pointers to the data type can be used before they are declared. This is a forward declaration, an exception to the rule that things must be declared before they are used.

Però non giustifica il fatto che nel caso sopra sia usabile e in quello sotto no.
Devo approfondire
Titolo: Re:Sintassi pascal
Inserito da: DragoRosso - Novembre 23, 2024, 08:26:32 am
Ecco spiegato l'arcano: https://www.freepascal.org/docs-html/ref/refse16.html (https://www.freepascal.org/docs-html/ref/refse16.html)

Traduco in Italiano:

Citazione
3.5 Dichiarazioni di tipo forward

I programmi spesso devono mantenere un elenco concatenato di record. Ogni record contiene quindi un puntatore al record successivo (e possibilmente anche al record precedente). Per la sicurezza dei tipi, è meglio definire questo puntatore come puntatore tipizzato, in modo che il record successivo possa essere allocato sull'heap utilizzando la chiamata New. Per fare ciò, il record dovrebbe essere definito in questo modo:
Type
TListItem = Record
Data : Integer;
Next : ^TListItem;
end;

Quando si tenta di compilare questo, il compilatore si lamenterà che il tipo TListItem non è ancora definito quando incontra la dichiarazione Next: Questo è corretto, poiché la definizione è ancora in fase di analisi.

Per poter avere l'elemento Next come puntatore tipizzato, è necessario introdurre una "dichiarazione di tipo forward":
Type
PListItem = ^TListItem;
TListItem = Record
Data : Integer;
Next : PTListItem;
end;

Quando il compilatore incontra una dichiarazione di puntatore tipizzata in cui il tipo referenziato non è ancora noto, rimanda la risoluzione del riferimento a un momento successivo. La definizione del puntatore è una "dichiarazione di tipo forward".

Il tipo referenziato dovrebbe essere introdotto in seguito nello stesso blocco Type. Nessun altro blocco può trovarsi tra la definizione del tipo puntatore e il tipo referenziato. Infatti, anche la parola Type stessa potrebbe non riapparire: in effetti avvierebbe un nuovo blocco di tipo, facendo sì che il compilatore risolva tutte le dichiarazioni in sospeso nel blocco corrente.

Nella maggior parte dei casi, la definizione del tipo referenziato seguirà immediatamente la definizione del tipo puntatore, come mostrato nell'elenco sopra. Il tipo definito forward può essere utilizzato in qualsiasi definizione di tipo successiva alla sua dichiarazione.

Nota che una dichiarazione di tipo forward è possibile solo con tipi e classi puntatore, non con altri tipi.

In pratica il compilatore quando il "blocco" in cui il type termina DEVE risolvere tutte le "definizioni" rimaste in piedi (come negli esempi). Quindi nel primo caso la sintassi è corretta, nel secondo invece no in quanto il secondo type "chiude" il blocco precedente senza definire il "tipo" puntato.

Ehhh se ne impara sempre una. Non sapevo neanche fosse possibile una "forward declaration" in Pascal ... ???

Il tutto è scaturito da un wrapper che ho generato di qualche decina di migliaia di righe e in alcuni punti avevo questo errore apparentemente senza senso, mentre in altri simili no.
Titolo: Re:Sintassi pascal
Inserito da: xinyiman - Novembre 23, 2024, 09:26:32 am
Mai usato la prima variante! Buono a sapersi
Titolo: Re:Sintassi pascal
Inserito da: DragoRosso - Novembre 23, 2024, 09:31:01 am
Mai usato la prima variante! Buono a sapersi
Neanche io, e non ne vedo neanche una grossa utilità.
Normalmente il puntatore ad un nuovo tipo viene definito dopo la definizione del tipo, in stile C.

Buona giornata
Titolo: Re:Sintassi pascal
Inserito da: bonmario - Novembre 23, 2024, 10:52:24 am
La differenza è che mentre nel primo c'è un solo "type" nel secondo ce ne sono due.

E nel secondo il compilatore si comporta come mi aspetto (cioè genera errore), mentre nel primo non dà errori.

Ah, grazie, non me ne ero nemmeno accorto !!!
Tra l'altro,m per abitudine ormai consolidata nel tempo, indipendentemente dal linguaggio di programmazione usato, tendo a dichiarare sempre prima quello che userò, anche se non è necessario ... nel tempo ho notato che in ogni caso mi aiuta a fare meno errori

Ciao, Mario