Supponiamo che tu abbia argomenti A1 & gt ;: A2 (controvariante) e tipi di ritorno B1 & lt ;: B2 (covariante).
Le funzioni corrispondenti sono tali che:
A1 = > B1 & lt ;: A2 = > B2
A volte, questo ha senso per me - lo afferrerò in un lampo di pensiero laterale. E poi qualche giorno dopo mi sono perso fino a quando non riesco a sforzarmi per un'altra ora o più.
Usando un esempio di Scala MOOC di Odersky (questo non è uno spoiler di assegnazione), Empty e NonEmpty sono entrambi sottotipi di IntSet.
Capisco che non è possibile passare un IntSet in una funzione che si aspetta un NonEmpty, poiché IntSet potrebbe essere un vuoto. Quindi il secondo (A2 = > B2) non può essere un sottotipo del primo (A1 = > B1). E capisco che può passare un NonEmpty in una funzione che si aspetta un IntSet, apparentemente perché la funzione chiamerà solo i metodi specifici IntSet che tutti i sottotipi hanno implementato. Pertanto il precedente può essere un sottotipo di quest'ultimo.
Allo stesso modo, una funzione che restituisce un IntSet non può essere un sottotipo di una funzione che restituisce un NonEmpty, poiché quello restituito IntSet non può necessariamente fare tutto ciò che il NonEmpty può fare. Viceversa, una funzione che restituisce un Can NonEmpty può essere un sottotipo di una funzione che restituisce un IntSet, poiché quello restituito NonEmpty sarà conforme al contratto IntSet.
Ma quello che ho problemi ad afferrare è, se può passare un NonEmpty in una funzione che si aspetta un IntSet, e se quella funzione fosse un sottotipo di una funzione che si aspetta un NonEmpty (apparentemente perché sta chiamando metodi NonEmpty specifici nella sua implementazione), allora perché dovresti voler usare quella funzione sottotitoli? Qualcuno ha esempi di questo essere utile? Perché usare le funzioni sottotipizzate?
Per me sembra solo pericoloso passare in un IntSet se sai che chiamerà funzionalità specifiche di NonEmpty.