JEP draft: Null-Restricted and Nullable Types (Preview)

44 views
Skip to first unread message

Francesco Vasco

unread,
Sep 10, 2024, 11:33:26 AM9/10/24
to jugm...@googlegroups.com
Ho recentemente letto il JEP in oggetto, il testo è qui: https://openjdk.org/jeps/8303099

Mi sembra molto interessante, questa funzionalità -per quanto banale- la apprezzo molto in Kotlin e mi fa piacere si stia finalmente pensando di adottarla in Java.
Immagino semplifichi anche la venuta del Valalla.

Al contempo, mi chiedo come andrà il supporto per di Optional, si continuerà a usare `Optional<User>!` oppure si opterà per il più semplice `User?` ?
Chissà quando arriveranno anche la safe navigation e l'elvis operator.

Ciao,
Vasco

Luca Guadagnini

unread,
Sep 11, 2024, 1:44:28 PM9/11/24
to jugm...@googlegroups.com
Ciao!

Sono due cose diverse, Optional è assenza di valore, la nullability è assenza di reference.

Come si è sempre detto, o come le convenzioni hanno sempre tentato di suggerire, l'Optional è un oggetto che dovrebbe essere ritornato da un metodo, e avrà molto più senso quando con l'introduzione del null-restricted dovrai specificare se il valore cercato (Optional<User> findById(...) {...}) o che hai tentato di generare è assente o meno.

Discorso diverso per i nullable-types, che così a naso li vedo molto più sensati nel passaggio parametri (di metodi o di costruttori) o per DTO/Entità/Aggregati/Viste.

Per l'elvis operator temo che possa non esserci nulla del genere, oppure opteranno per qualcosa di diverso, questo per via dell'operatore ternario che potrebbe generare confusione (e la readability è sempre una questione annosa per Java). In Kotlin ad esempio hanno preferito l'if-expression proprio perché l'opertore ternario, se introdotto, avrebbe fatto a botte con l'elvis operator e la safe navigation.

Pensiero finale sull'Optional: non ricordo bene se i motivi dei factory method dell'Optional siano per sottolineare la sua finalità, ma è interessante far notare che Optional.of(...) non permette valori nullable, mentre per compatibilità e per elasticità hanno aggiunto l'Optional.ofNullable(...). Ricordo pure una discussione frizzante di Mario Fusco con Brian Goetz su Twitter/X a tal proposito, perché per lui avere due metodi non erano necessari. Tuttavia ho questa percezione che molte delle cose che nell'OpenJDK stanno realizzando e portando avanti, sono frutto di una visione e di un obiettivo ben preciso e quando possono aggiungono funzionalità che possono appoggiare quella visione. Optional ne è un esempio, poiché di Valhalla se ne parlava già dai tempi di Java 8 (sì sì ne parlo al passato, ma so benissimo che in qualche realtà c'è ancora, vero? VERO? MA SMENTITEMI VI PREGO!) e sapevano che prima o poi i value-type sarebbero arrivati (tant'è che OpitonalInt, OptionalLong e OptionalDouble verranno deprecati).

Saluti!
Luca!

--
jugmilano.it - youtube.com/c/JUGMilano - twitter.com/JUGMilano - gitter.im/jugmilano/jugmilano
---
Hai ricevuto questo messaggio perché sei iscritto al gruppo "JUGMilano - JVM User Group Milano" di Google Gruppi.
Per annullare l'iscrizione a questo gruppo e non ricevere più le sue email, invia un'email a jugmilano+...@googlegroups.com.
Per visualizzare questa discussione sul Web, visita https://groups.google.com/d/msgid/jugmilano/1125100230.9270772.1725982344029%40mail.yahoo.com.

Francesco Vasco

unread,
Sep 12, 2024, 4:07:02 PM9/12/24
to jugm...@googlegroups.com

Ciao Luca

Il 11/09/24 19:44, Luca Guadagnini ha scritto:
Sono due cose diverse, Optional è assenza di valore, la nullability è assenza di reference.

Sintatticamente sono diversi, ma nella mia testa hanno la stessa semantica, questo a prescindere se sia l'argomento o il valore risultante della funzione.

Se "null" e "Optional.EMPTY" avessero due significati diversi, una funzione di tipo Optional potrebbe restituire null, ma questa è considerata una cattiva pratica.

Vasco


Luca Guadagnini

unread,
Sep 13, 2024, 12:31:53 PM9/13/24
to jugm...@googlegroups.com
Scusa non credo di aver capito bene il commento, null e Optional.EMPTY hanno due significati diversi a prescindere di quello che hai in mente, o meglio, capisco che per semplificare si porti a pensare che l'Optional vuoto possa essere un'analogia al null, ma sempre di analogia parliamo, perché di fatto Optional è comunque un oggetto (in futuro un value-type) e si cadrebbe nell'errore di pensare che non sia altro un null-object pattern solo con un livello di astrazione in più.

Poi è ovvio che ognuno è libero di piegare gli strumenti in funzione a quello che vuole realizzare, se l'Optional gli torna utile anche nel passaggio parametri, ottimo, basta che sappia gestire il trade-off dello scenario.

Però questa è una vecchia diatriba di come usare l'Optional, più che nullable o null-restrict. Al momento, nel mio caso perlomeno, ho sempre usato l'Optional solo per i find nel repository pattern o per qualche classe di servizio (anche in Kotlin).

--
jugmilano.it - youtube.com/c/JUGMilano - twitter.com/JUGMilano - gitter.im/jugmilano/jugmilano
---
Hai ricevuto questo messaggio perché sei iscritto al gruppo "JUGMilano - JVM User Group Milano" di Google Gruppi.
Per annullare l'iscrizione a questo gruppo e non ricevere più le sue email, invia un'email a jugmilano+...@googlegroups.com.

Francesco Vasco

unread,
Sep 14, 2024, 2:08:57 AM9/14/24
to jugm...@googlegroups.com
> null e Optional.EMPTY hanno due significati diversi

Posso chiederti di chiarire meglio quali sono?

Nella mail precedente lo spiegasti così:

> Optional è assenza di valore, la nullability è assenza di reference

Per essere diversi, dovrebbe voler dire: Optional è assenza di un valore (quindi non c'è neanche il riferimento), la nullability è assenza di reference (anche se il valore esiste).
Questo perché se la null fosse l'assenza di riferimento e di valore, allora si ricadrebbe nel caso Optional.

Quindi, onestamente, non capisco.
Inoltre, nelle API di Java non esistono metodi che ritornano null, Optional.EMPTY o Optional.of(qualcosa); se possono tornare Optional non tornano mai null e viceversa.
Un esempio nella JRE mi aiuterebbe a capire cosa intendi.

Grazie,
Vasco

Stefano Fago

unread,
Sep 14, 2024, 4:18:26 AM9/14/24
to jugm...@googlegroups.com
Non so sei aiuta,  ma la distinzione proposta da Luca può  essere riformulata come differenti obiettivi e strumenti.

Optional è un container ( pseudo monad ) che è uno strumento derivante dallo stile FP e non significa quindi solo mancanza di valore ma avere l'occasione o l'intenzione di operare secondo quel paradigma. Nell'ibridizzazione oop/fp logicamente questo crea un po di confusione per cui l'uso di questo container non è sempre corretto/valido/efficace. L'Optional Java x come sviluppato ora è candidato per diventare una Value Class con i presumibili vantaggi anche di performance.

I nuovi costrutti sintattici sono un'altro discorso è non sono container e rientrano non solo come miglioria sintattica ma anche di evoluzione di compilatore e jvm.

Rientrano tutti e due nell'ottica di diminuire i side-effect della presenza di NULL,? SI!
Sono strumenti equivalenti? NO!

La veloce evoluzione è potenziamento di Java sono causa di difficoltà di controllo e varietà di use-cases di sviluppo che si colgono/maturano nel tempo come accaduto nell'enumerazioni.

Come riportato da Luca, il "Team Core" ha dei target a lungo termine che non sempre sono immediatamente intuibili... Personalmente cerco di seguire ma anche x altri linguaggi è un po fastidioso e allora preferisco godermi quello che arriva!

Buon weekend e sempre complimenti a tutti x questa interessante Community

Stefano

--
jugmilano.it - youtube.com/c/JUGMilano - twitter.com/JUGMilano - gitter.im/jugmilano/jugmilano
---
Hai ricevuto questo messaggio perché sei iscritto al gruppo "JUGMilano - JVM User Group Milano" di Google Gruppi.
Per annullare l'iscrizione a questo gruppo e non ricevere più le sue email, invia un'email a jugmilano+...@googlegroups.com.

Gian Carlo Pace

unread,
Sep 14, 2024, 5:28:49 AM9/14/24
to JVM User Group Milano (JUG Milano)
Provo a dare la mia risposta.

TL;DR: Optional ritorna sempre un risultato dello stesso tipo a prescindere che la funzione abbia un risultato ammissibile o no, null non ha nessun tipo e quindi deve essere sempre testato in qualche modo per gestire il caso eccezionale.

Da un punto di vista matematico una funzione  è una relazione tra gli elementi di due insiemi detti dominio e condominio. 
Se per ogni elemento del dominio puoi trovare un elemento nel codominio la funzione è completa altrimenti si dice parziale (es. y=1/x è parziale in quanto non è definita per x=0). 

Analogamente tornando all’informatica se sostituiamo i tipi al posto di degli insiemi, una funzione fun f(num: Int): String trasforma dati dal dominio delle stringhe al codominio degli interi.

Ma molto spesso le funzioni in informatica sono parziali non avendo sempre un valore di ritorno e ci obbligano e gestire i casi eccezionali ritornando null oppure lanciando una eccezione. 

null non è tipo ma indica l’assenza di un tipo e purtroppo può essere sostituito a qualsiasi tipo, pertanto non fa parte dell’insieme dei tipi di ritorno (ovvero del codominio) anche se può essere ritornato. 
Non facendo null parte del codominio una funzione che ritorna null, risulta essere parziale.

Questo ci obbliga a scrivere if (result == null) { … } else { … }. Lo stesso accadrebbe se io lanciassi un’eccezione dovendo gestire l’eccezione fuori dal normale flusso della funzione.

In FP si tende a lavorare con funzioni complete e pure (che hanno vantaggi nella correttezza della loro composizione) per la logica di dominio, lasciando ai bordi della computazione i side effect e i casi eccezionali. 

La monade Optional ad esempio trasforma una funzione parziale in una completa (o totale) ritornando un valore del codominio anche quando la funzione originale non avrebbe nessun valore da ritornare. Optional.Empty è un valore del codominio esattamente come Optional.of(3) e mi permette di trattare la computazione in modo analogo in entrambi i casi.

E’ la stessa idea che dei null objects in OOP ma le monadi hanno un vantaggio enorme: sono componibili come le funzioni e come esse mantengono le proprietà matematiche della composizione.

Ciao,
— 
gk

Difference between null and empty ("") Java String - Stack Overflow

--
jugmilano.it - youtube.com/c/JUGMilano - twitter.com/JUGMilano - gitter.im/jugmilano/jugmilano
---
Hai ricevuto questo messaggio perché sei iscritto al gruppo "JUGMilano - JVM User Group Milano" di Google Gruppi.
Per annullare l'iscrizione a questo gruppo e non ricevere più le sue email, invia un'email a jugmilano+...@googlegroups.com.

Gian Carlo Pace

unread,
Sep 14, 2024, 5:39:51 AM9/14/24
to JVM User Group Milano (JUG Milano)
Analogamente tornando all’informatica se sostituiamo i tipi al posto di degli insiemi, una funzione fun f(num: Int): String trasforma dati dal dominio delle stringhe al codominio degli interi.
My bad: ho fatto refactoring della funzione senza modificare la documentazione.

fun f(num: Int): String trasforma dati dal dominio degli interi al codominio delle stringhe.

Luca Guadagnini

unread,
Sep 14, 2024, 5:47:46 AM9/14/24
to jugm...@googlegroups.com
Grazie Stefano e Gian Carlo per il contributo! Dimentico sempre le definizioni teoriche e matematiche che la monade si porta appresso :) nonché il meme.

Buon weekend!

--
jugmilano.it - youtube.com/c/JUGMilano - twitter.com/JUGMilano - gitter.im/jugmilano/jugmilano
---
Hai ricevuto questo messaggio perché sei iscritto al gruppo "JUGMilano - JVM User Group Milano" di Google Gruppi.
Per annullare l'iscrizione a questo gruppo e non ricevere più le sue email, invia un'email a jugmilano+...@googlegroups.com.

Francesco Vasco

unread,
Sep 14, 2024, 12:01:40 PM9/14/24
to JVM User Group Milano (JUG Milano)
Ciao Gian Carlo,

> null non è tipo ma indica l’assenza di un tipo e purtroppo può essere sostituito a qualsiasi tipo, pertanto non fa parte dell’insieme dei tipi di ritorno (ovvero del codominio) anche se può essere ritornato.

Penso che la differenza principale tra i nostri due punti di vista sia proprio questa, provo a spiegarti come la vedo io.

In Java, è "void" a non essere un tipo, un non qualcosa che fa praticamente solo eccezioni: solo i risultati dei metodi possono essere void, non puoi tornare void ("return void" oppure "return println()"), puoi anche non chiamare il return del tutto.
null in Java è una costante, un valore perfettamente legittimo per qualsiasi riferimento pur non estendendo Object.

A mio avviso, il problema principale è che Java ha una dichiarazione fuorviante, perché quello che in Java si scrive:

    String f(int num)

In Ceylon si scrive:

    String|Null f(Int num)

Sono esattamente la stessa dichiarazione, ma in Ceylon è evidente che "null" fa parte del codominio.
In Java questa cosa sarà possibile quando completeranno il JEP che ho citato all'inizio della discussione.


Se quanto scritto sopra è corretto, questo implica che quello che in Java è:

    Optional<String> f(int num)

In Ceylon è:

    Optional<String>|Null f(Int num)

Ne consegue che a il problema del null hai aggiunto Optional.
Dico questo ignorando le buone pratiche, suppongo che il tuo discorso verta sui linguaggi e la semantica della dichiarazione è quella.


> La monade Optional ad esempio trasforma una funzione parziale in una completa

Questo è vero solo se la funzione non può tornare null, non può lanciare eccezioni e non può arrestare il programma, non mi sembra il caso di Java.


> Questo ci obbliga a scrivere if (result == null) { … } else { … }
> E’ la stessa idea che dei null objects in OOP ma le monadi hanno un vantaggio enorme: sono componibili come le funzioni e come esse mantengono le proprietà matematiche della composizione.

Queste sono differenze sintattiche su cui avrei altro da dire (e l'ho già detto in un talk al JUG), però la mia domanda riguarda le differenze semantiche.

Luca: null e Optional.EMPTY hanno due significati diversi

Qual'è il significato di null diverso da quello di Optional.EMPTY?


Vi aggiungo un rebus, se vi va: nell'interfaccia java.util.Map<K, V>, quale dovrebbe essere la firma del metodo "get"?


Grazie per questa discussione,
Vasco

Stefano Fago

unread,
Sep 14, 2024, 12:25:27 PM9/14/24
to jugm...@googlegroups.com
#joke #porkware  Supplier<Void> voidUp = ()->{ System.out.println("VOID!"); return null; };   

Quanto riportato mi sembra corretto e anche per i parametri si può fare la stessa similitudine, cioè in una signature

String method(Param)   implica in realtà    String|null method(Param|null)

Ed è anche per questo che verrà inserita la nuova sintassi...
Si cade quindi nel discorso Type System e qui... viene la domanda: forse mi sono perso una parte e mi scuso!
Typescript che è stato scritto da zero ha un accento forte sul Type System
con scelte più o meno plausibili ma anche lì, dove il type system è molto interessante, ci sono dei momenti un pò strani: undefined, null, unknown, any e le alberature derivanti...

Non intervengo oltre e cito solo Manifold, che può risultare utile se si vogliono sperimentare sintassi/semantiche differenti
ma il resto è derivato dall'evoluzione del linguaggio...

Però qui mi fermo... perchè ho perso sicuramente un pezzo del discorso...

Mi scuso ancora con tutti!

Buon Weekend!

Stefano


--
jugmilano.it - youtube.com/c/JUGMilano - twitter.com/JUGMilano - gitter.im/jugmilano/jugmilano
---
Hai ricevuto questo messaggio perché sei iscritto al gruppo "JUGMilano - JVM User Group Milano" di Google Gruppi.
Per annullare l'iscrizione a questo gruppo e non ricevere più le sue email, invia un'email a jugmilano+...@googlegroups.com.

Agostino Carandente

unread,
Sep 14, 2024, 3:47:53 PM9/14/24
to jugm...@googlegroups.com
Il 14 set 2024, 18:25 +0200, jugm...@googlegroups.com, ha scritto:

Typescript che è stato scritto da zero ha un accento forte sul Type System
con scelte più o meno plausibili ma anche lì, dove il type system è molto interessante, ci sono dei momenti un pò strani: undefined, null, unknown, any e le alberature derivanti...

Il motivo per queste stranezze è che non è nato da zero, ma 1) aveva la necessità di coprire i tipi di JavaScript 2) ha fatto diverse scelte di ergonomia per rendere più semplice possibile la transizione JS→TS; alcune di queste scelte negli anni sono state riviste ma l’impronta di vede ancora 

Gian Carlo Pace

unread,
Sep 14, 2024, 6:49:30 PM9/14/24
to JVM User Group Milano (JUG Milano)
Ciao Fra,

null non è tipo ma indica l’assenza di un tipo e purtroppo può essere sostituito a qualsiasi tipo, pertanto non fa parte dell’insieme dei tipi di ritorno (ovvero del codominio) anche se può essere ritornato.

Penso che la differenza principale tra i nostri due punti di vista sia proprio questa, provo a spiegarti come la vedo io.

In Java, è "void" a non essere un tipo, un non qualcosa che fa praticamente solo eccezioni: solo i risultati dei metodi possono essere void, non puoi tornare void ("return void" oppure "return println()"), puoi anche non chiamare il return del tutto.
null in Java è una costante, un valore perfettamente legittimo per qualsiasi riferimento pur non estendendo Object.

A mio avviso, il problema principale è che Java ha una dichiarazione fuorviante, perché quello che in Java si scrive:

    String f(int num)

In Ceylon si scrive:

    String|Null f(Int num)

Sono esattamente la stessa dichiarazione, ma in Ceylon è evidente che "null" fa parte del codominio.
In Java questa cosa sarà possibile quando completeranno il JEP che ho citato all'inizio della discussione.
Non conosco Celyon ma dalla sintassi mi sembra che le definizioni siano alquanto diverse. 

In Java null non è un tipo ma indica l’assenza di un tipo (non c’è la reference e non posso sapere quale sia il tipo sottostante). Invece scrivere String|Null sembra essere un sum type in cui si sommano il tipo String e il tipo Null e quindi Null è un tipo. Sono due cose molto differenti. 
Tale definizione sembra molto simile a quella di Optional dei linguaggi che usano gli algebraic data type. Per esempio in Haskell lo definiamo come

data Maybe a = Nothing | Just a

Però la semantica di Nothing in Haskell o di Null in Celyon è quella di un tipo che esplicitamente significa che per un certo tipo di ritorno non c’è un valore. 
In java null non è un tipo ma l’indicazione di una reference mancante per cui la semantica gliela dà il programmatore nel contratto del metodo. 
Può succedere di trovare metodi in Java che ritornano null non solo per la mancanza di un valore di ritorno ma anche in caso di errore: la semantica gliela diamo noi programmatori e non è legata a nessun tipo specifico (come nel caso Null di Celyon). 

Se quanto scritto sopra è corretto, questo implica che quello che in Java è:

    Optional<String> f(int num)

In Ceylon è:

    Optional<String>|Null f(Int num)

Ne consegue che a il problema del null hai aggiunto Optional.
Dico questo ignorando le buone pratiche, suppongo che il tuo discorso verta sui linguaggi e la semantica della dichiarazione è quella.
Scrivere Optional<String>|Null f(Int num) non ha molto senso perché se espliciti Optional con i sum type Optional a = Some a | Null e quindi il tipo di ritorno diventa String | Null | Null che sarebbe equivalente a String | Null ma non a String | null.

La monade Optional ad esempio trasforma una funzione parziale in una completa

Questo è vero solo se la funzione non può tornare null, non può lanciare eccezioni e non può arrestare il programma, non mi sembra il caso di Java.
Certo ma infatti scegliere un paradigma più funzionale all’interno di Java è una scelta dato che Java nasce nell’OOP. 


Questo ci obbliga a scrivere if (result == null) { … } else { … }
E’ la stessa idea che dei null objects in OOP ma le monadi hanno un vantaggio enorme: sono componibili come le funzioni e come esse mantengono le proprietà matematiche della composizione.
Queste sono differenze sintattiche su cui avrei altro da dire (e l'ho già detto in un talk al JUG), però la mia domanda riguarda le differenze semantiche.
Qual'è il significato di null diverso da quello di Optional.EMPTY?
Qui non ti seguo per cui provo a dare una risposta. Il NullObject è un modo di utilizzare un tipo per indicare l’assenza di un valore utilizzando un tipo invece che un non-tipo (null). La semantica di null non è per niente definita e come dicevo prima è definita dal programmatore. 

Vi aggiungo un rebus, se vi va: nell'interfaccia java.util.Map<K, V>, quale dovrebbe essere la firma del metodo "get"?
Per come la vedo io, un linguaggio di programmazione non è OOP o FP ma si trova in uno spettro con caratteristiche più o meno OOP o FP. Come definisci l’interfaccia dipende da dove vuoi posizionare il linguaggio. Se vuoi tenerti più nell’OOP ritorni un null come nel o lanci un’eccezione, se vuoi posizionarti nel FP allora usi Optional e Either per modellare tutti i side effects. Una cosa che mi fa propendere per Optional e Either è che rende i side effects espliciti nella firma del metodo, mentre il null e trhow exception non lo sono. 

A questo riguardo c’è un bel talk di Erik Mejier https://www.youtube.com/watch?v=sTSQlYX5DU0

Ciao!
— 
gk

Alessandro Sivieri

unread,
Sep 15, 2024, 12:41:28 AM9/15/24
to jugm...@googlegroups.com
Ciao,

    Optional<String>|Null f(Int num)

A mio avviso da un punto di vista pratico sia Optional che nullable sono in realtà la stessa cosa, come detto dall'op, anche se da un punto di vista semantico non lo sono per i motivi già citati, perchè alla fine tutto si riduce all'utilizzo che ne fa il programmatore.

Come dice Francesco qui sopra, tecnicamente una funzione che ritorna un Optional implicitamente ritorna anche null, il fatto che lo faccia o meno dipende da cosa decide di fare l'autore all'interno della funzione stessa. Se uno vuole seguire uno stile più FP, allora userà gli Optional e wrapperà qualunque null dentro l'Empty; se invece uno vuole seguire più lo stile OO, allora continuerà a ritornare i null del caso, ed avere il nullable esplicitato come in Kotlin costringe l'utilizzatore della funzione ad esplicitarne la gestione, nella speranza di evitare le eccezioni dovute a mancate reference non gestite.

Alessandro

Francesco Vasco

unread,
Sep 15, 2024, 6:10:08 AM9/15/24
to JVM User Group Milano (JUG Milano)
Ciao Gian Carlo,
ti ringrazio ancora per la discussione, ne sto approfittando per rinfrescarmi un po' di concetti.

Mi spiace per gli esempi in Cyelon, provo ad usare la matematica.


Sezione "3.10.7. The Null Literal" del "The Java® Language Specification", edizione 21.

Immagine incorporata



Sezione "4.12.2. Variables of Reference Type" del "The Java® Language Specification", edizione 21.

Immagine incorporata

Se comprendo bene, la dichiarazione di una variabile di tipo T, equivale a: T ∪ {null}
Faccio notare che questo non è sempre vero, se scrivo: catch (e: A | B | C), la variabile "e" può essere solo dei tipi enumerati, mai null.


Francesco

Luca Guadagnini

unread,
Sep 15, 2024, 9:45:16 AM9/15/24
to jugm...@googlegroups.com
Visto che in quel della Val d'Adige la giornata è uggiosa e alquanto ventosa...

Faccio notare però che la sintassi espressa dal catch, o meglio multi-catch, non è né un sum type né un union type, è uno zucchero sintattico per accorpare i casi di catch uguali tra loro, zucchero che introduce l'espressione union-of-types come si può leggere nella specifica di seguito: https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20 e non ha nulla a che vedere con la definizione di un tipo. Tant'è che linguaggi che hanno il try-catch e tipi algebrici (C#, Kotlin, Scala, Typescript, ecc...) hanno evitato di implementare la funzionalità del multi-catch di Java, proprio per non generare confusione, visto che le pipe vengono spesso usate per la dichiarazione di union type.

Per ribadire la differenza tra linguaggi OOP come Java e uno funzionale come Haskell, ci si può divertire con il seguente esempio.

In Java quello che dovrebbe essere possibile in futuro tramite lo switch-expression e Valhalla (prima si chiamavano universal generics) è la seguente sintassi:

Optional<User> findUserById(...)

switch (findUserById(...)) {
  case Optional.<User>of user -> user // user viene già estrapolato da Optional automaticamente
  case Optional.<User>ofNullable -> ... // caso in cui l'Optional sia vuoto
  null -> ... // caso in cui sia l'oggetto Optional stesso a essere a null
}

E questo equivale, riprendendo sempre la teoria degli insiemi, a qualcosa di più articolato: un reference type in Java equivale a T, o meglio a T', dove T' sono tutti i valori di T più il null, cioè T' = T U {null} mentre l'Optional che chiamiamo O, per sua definizione è O T = T U { 0 }, ovvero contiene tutti i valori di T senza il null più l'insieme vuoto, ma essendo Optional stesso un tipo Java, dovremmo definirlo come O' T = O { T U { 0 } } U { null }. Spero di aver scritto tutto giusto.

Tutto questo con il miglioramento della nullability e l'introduzione del null-restrict si può prevedere di rifattorizzare il metodo:

Optional<User>! findUserById(...)

così da risparmiarci un caso inutile:

switch (findUserById(...)) {
  case Optional.<User>of user -> user // user viene già estrapolato da Optional automaticamente
  case Optional.<User>ofNullable -> ... // caso in cui l'Optional sia vuoto
}

così da avere da gestire solo O T = T U { 0 } da renderlo, almeno durante il pattern matching, del tutto simile a Haskell:

findUserById :: Int -> [User] -> Maybe User

... case findUserById id users of
  Just user -> "Hello, " ++ userName user ++ "!"
  Nothing -> "User not found."

visto che in Haskell non esiste il literal nil o null.

Ecco ora credo di aver digerito il pranzo, vado a farmi due passi se la meteopatia non coglie.
Buona domenica!
Luca!

--
jugmilano.it - youtube.com/c/JUGMilano - twitter.com/JUGMilano - gitter.im/jugmilano/jugmilano
---
Hai ricevuto questo messaggio perché sei iscritto al gruppo "JUGMilano - JVM User Group Milano" di Google Gruppi.
Per annullare l'iscrizione a questo gruppo e non ricevere più le sue email, invia un'email a jugmilano+...@googlegroups.com.

Gian Carlo Pace

unread,
Sep 16, 2024, 4:58:50 AM9/16/24
to JVM User Group Milano (JUG Milano)
Ciao Fra,

Sempre bello anche per me scambiare vedute e opinioni :) 

Inizio però a non comprendere il punto cui vuoi arrivare. 

Quando dici che la dichiarazione di una variabile di tipo T equivale a un tipo T∪{null}, non mi trovi d’accordo. 

Quello che dice la specifica è che la variabile può contenere o il valore del tipo (T) o una null reference e non che la definizione del tipo uno union type T | {null} dato che null non è un tipo.
Sono due cose differenti e IMO rappresentano la radice del billion-dollar mistake, proprio perché permettono di trattare una null reference come una specie di wildcard di tipi. 

{null} non è un tipo proprio perché indica l’assenza di un tipo (esattamente il contrario di un tipo) e quindi non ha una semantica sua*. 

Un tipo che si chiami Null o Nothing o Empty invece ha una sua semantica. 

Su questo siamo d’accordo?
— 
gk


(*) Potrei ad esempio avere un metodo che tenta di stabilire una connessione e se va in errore ingoia l’eccezione e ritorna null. Ciò è molto differente dalla semantica di non ho un valore di un optional. 


On 15 Sep 2024, at 12:10, 'Francesco Vasco' via JUGMilano - JVM User Group Milano <jugm...@googlegroups.com> wrote:

Ciao Gian Carlo,
ti ringrazio ancora per la discussione, ne sto approfittando per rinfrescarmi un po' di concetti.

Mi spiace per gli esempi in Cyelon, provo ad usare la matematica.


Sezione "3.10.7. The Null Literal" del "The Java® Language Specification", edizione 21.

<1726392925842blob.jpg>



Sezione "4.12.2. Variables of Reference Type" del "The Java® Language Specification", edizione 21.

<1726394127223blob.jpg>

Se comprendo bene, la dichiarazione di una variabile di tipo T, equivale a: T ∪ {null}
Faccio notare che questo non è sempre vero, se scrivo: catch (e: A | B | C), la variabile "e" può essere solo dei tipi enumerati, mai null.


Francesco

--
jugmilano.it - youtube.com/c/JUGMilano - twitter.com/JUGMilano - gitter.im/jugmilano/jugmilano
---
Hai ricevuto questo messaggio perché sei iscritto al gruppo "JUGMilano - JVM User Group Milano" di Google Gruppi.
Per annullare l'iscrizione a questo gruppo e non ricevere più le sue email, invia un'email a jugmilano+...@googlegroups.com.
Per visualizzare questa discussione sul Web, visita https://groups.google.com/d/msgid/jugmilano/61544790.12036141.1726395002355%40mail.yahoo.com.
<1726392925842blob.jpg><1726394127223blob.jpg>

Francesco Vasco

unread,
Sep 16, 2024, 7:01:35 AM9/16/24
to JVM User Group Milano (JUG Milano)
Ciao Gian Carlo,
piacere che condivido.

> {null} non è un tipo proprio perché indica l’assenza di un tipo (esattamente il contrario di un tipo) e quindi non ha una semantica sua*. 
> Un tipo che si chiami Null o Nothing o Empty invece ha una sua semantica.

È su questo che non mi ritrovo, forse ho male interpretato queste righe o mal compreso la documentazione.

Dalla sezione 4.1

> In practice, the programmer can ignore the null type and just pretend that null is merely a special literal that can be of any reference type.

Se comprendo bene, in soldoni possiamo far finta che il tipo null non esista, però la stessa sezione dice che esiste:

1. There is also a special null type, the type of the expression null (§3.10.7, §15.8.1), which has no name.
2. Because the null type has no name, it is impossible to declare a variable of the null type or to cast to the null type.
3. The null reference is the only possible value of an expression of null type.
4. The null reference can always be assigned or cast to any reference type (§5.2, §5.3, §5.5).

Per come lo leggo io:

1. Esiste un tipo anonimo {null}
2. Non c'è modo di usare il tipo {null}
3. L'unico valore di {null} è null (lo si può intendere come un singleton o come un booleano con metà dei valori)
4. Ogni volta che dichiari una variabile di un tipo T, questa potrà anche essere null (T ∪ {null}), se provi a fare il cast verso un tipo T, il cast ha successo sia se può essere assegnato a T sia se è null (T ∨ null).

Cosa sto sbagliando?
Potresti indicarmi qualche riferimento da poter leggere per comprendere meglio cosa intendi?

Grazie,
Francesco

Gian Carlo Pace

unread,
Sep 16, 2024, 9:51:30 AM9/16/24
to JVM User Group Milano (JUG Milano)
Ciao Francesco, 

Forse ho compreso quale sia il punto di disconnessione delle nostre visioni ovvero il livello di astrazione differente cui guardiamo il problema. 

Da un punto di vista di astrazione basso nella JVM null è stato implementato come un tipo anonimo che può essere assegnato a qualunque variabile ma che non può essere usato per istanziare una variabile (cosa che sarebbe paradossale dato che indica l’assenza di una reference). 

Io guardo il problema da un punto di vista di astrazione più alto. 

Cosa è un tipo: un tipo è una categorizzazione di un insieme di valori che possiamo dare ad una variabile a cui possiamo dare un nome (ho provato a mettere insieme un po’ di definizioni spero questa sia good enough). 

Ciò che ci fornisce Java ovvero l’insieme di literal null più un tipo anonimo che non posso istanziare possono essere considerati un tipo a tutti gli effetti? No perché non servono a categorizzare valori di variabili, non li posso istanziare e non li posso nemmeno nominare (null è il literal non il nome del tipo) per cui quando scriviamo String | {null}  mettiamo le parentesi graffe perché null non è il nome del tipo. 
Inoltre posso assegnare il literal null ai tipi di tutte le variabili. 

Questo perché l’intenzione dell’implementazione nella JVM non è che venga trattato come un tipo qualunque ma come uno che indica l’assenza di reference. Ed infatti scrivono: "the programmer can ignore the null type and just pretend that null is merely a special literal that can be of any reference type”. Non vuole essere trattato come un tipo. Non posso fare instanceof null o metterlo nel catch come dicevi tu.

Questa particolarità crea la discontinuità dei valori di ritorno di una funzione e non fornisce nessun significato semantico dato che è anonimo. Se potessi dire typedef Empty = {null} e poi definissi Optional = Some(T) | Empty allora potrei fornirgli una semantica ma così com’è, senza nome e con un solo valore pari al literal, la semantica viene fornita dal programmatore (come ho spiegato dell’esempio precedente della connessione mancata che torna null). 

Per questo una funzione che torna null non potrà mai essere considerata totale (o completa), per questo server Optional se vogliamo usare un approccio più FP in Java (che non lo ha prescritto il medico però :) ). 

Ti torna di più così?

— 
gk 

--
jugmilano.it - youtube.com/c/JUGMilano - twitter.com/JUGMilano - gitter.im/jugmilano/jugmilano
---
Hai ricevuto questo messaggio perché sei iscritto al gruppo "JUGMilano - JVM User Group Milano" di Google Gruppi.
Per annullare l'iscrizione a questo gruppo e non ricevere più le sue email, invia un'email a jugmilano+...@googlegroups.com.

Francesco Vasco

unread,
Sep 16, 2024, 11:52:35 AM9/16/24
to JVM User Group Milano (JUG Milano)
Ciao Gian Carlo,

> Ciò che ci fornisce Java ovvero l’insieme di literal null più un tipo anonimo che non posso istanziare possono essere considerati un tipo a tutti gli effetti?

Si.
Perdonami ma qui ti perdo inesorabilmente.
Nel mio limitato cervello, se la specifica dichiara che esiste, allora esiste, indipendentemente dal fatto che sia anonimo, che sia un letterale, da quale si supponga sia l'intenzione dell'implementazione JVM oppure se voglia o meno essere trattato come tipo.


> non fornisce nessun significato semantico dato che è anonimo

Sono 29 anni che null è usato in Java, è il valore predefinito per qualsiasi riferimento, uno schifo di semantica dovrà pure averla :-)


> Per questo una funzione che torna null non potrà mai essere considerata totale (o completa)

La funzione java.util.function.Function.identity() la ritengo pura, biettiva ed è anche una involuzione; mi sembra decisamente severo discriminarla perché torna null, null fa parte tanto del dominio quanto del codominio.


Comunque forse ho capito le divergenze, nessun problema.
Se decidi di fare un talk su questo argomento, io ci sono!

Francesco

Gian Carlo Pace

unread,
Sep 16, 2024, 12:28:13 PM9/16/24
to JVM User Group Milano (JUG Milano)
Ciao Francesco,

Ciò che ci fornisce Java ovvero l’insieme di literal null più un tipo anonimo che non posso istanziare possono essere considerati un tipo a tutti gli effetti?
Si.
Perdonami ma qui ti perdo inesorabilmente.
Provo a essere più sintetico e spero più chiaro: 
Un tipo ha un nome e serve a categorizzare valori di variabili che si possono istanziare.
Il null type non ha un nome e non categorizza valori e non si può neppure istanziare. 
Definirlo tipo perché è implementato con un tipo dentro la JVM mi sembra far fetched. 

Se anche questo non ti convince provo con:  null type è un tipo ma null non lo è :)

Nel mio limitato cervello, se la specifica dichiara che esiste, allora esiste, indipendentemente dal fatto che sia anonimo, che sia un letterale, da quale si supponga sia l'intenzione dell'implementazione JVM oppure se voglia o meno essere trattato come tipo.
Per me (e qui penso ci disconnettiamo) Il problema non è che non esista dentro la JVM, è a cosa serva e come sia usato e lo dicono chiaramente anche loro nella specifica, non per essere usato come gli altri tipi ma come un placeholder di reference mancante. 
Per cui io non lo uso come un tipo come tutti gli altri.

non fornisce nessun significato semantico dato che è anonimo
Sono 29 anni che null è usato in Java, è il valore predefinito per qualsiasi riferimento, uno schifo di semantica dovrà pure averla :-)
E sono 29 anni che si dice in giro non sia stata l’idea più riuscita del linguaggio dato che ognuno gli dà il significato che vuole e tutti fanno if (pippo==nuill) per i più disparati motivi:) (ricordiamoci sempre di quest’uomo https://en.wikipedia.org/wiki/Tony_Hoare)

Comunque forse ho capito le divergenze, nessun problema.
Se decidi di fare un talk su questo argomento, io ci sono!
è una bella idea :) Diciamo che per fare un talk sulla type theory non mi sento ancora pronto. Magari tra una ventina d’anni :) 

Ciao e grazie per lo scambio! Ho imparato un sacco di cose sulla specifica.  
— 
gk

Andrea Iacono

unread,
Sep 17, 2024, 4:38:18 AM9/17/24
to jugm...@googlegroups.com
Ciao,
E sono 29 anni che si dice in giro non sia stata l’idea più riuscita del linguaggio dato che ognuno gli dà il significato che vuole e tutti fanno if (pippo==nuill) per i più disparati motivi:) (ricordiamoci sempre di quest’uomo https://en.wikipedia.org/wiki/Tony_Hoare)


non siamo troppo duri col buon vecchio Tony: ci ha anche regalato quicksort e quickselect :-)

Ciao,
Andrea



Reply all
Reply to author
Forward
0 new messages