350 lines
11 KiB
Markdown
350 lines
11 KiB
Markdown
# 24. Casts et conversions
|
|
|
|
## 24.1 Principe général — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
Saselang distingue explicitement :
|
|
|
|
```text
|
|
conversion de valeur
|
|
cast de hiérarchie nominale
|
|
bitcast de représentation binaire
|
|
```
|
|
|
|
Ces mécanismes ne sont pas des alias.
|
|
|
|
`bitcast<T>(value)` est défini au chapitre 20 et ne constitue jamais une conversion numérique.
|
|
|
|
## 24.2 Conversions implicites numériques — V1 REQUIS — FIGÉ
|
|
|
|
Il n'existe aucune promotion numérique implicite générale entre deux valeurs déjà typées de types primitifs différents.
|
|
|
|
```text
|
|
int8 small = ...;
|
|
int32 large = small; // ERROR
|
|
int32 explicitLarge = small::toInt32(); // OK
|
|
```
|
|
|
|
Le typage contextuel d'un littéral non encore typé reste une règle distincte.
|
|
|
|
## 24.3 Upcast — V1 REQUIS — FIGÉ
|
|
|
|
Un upcast compatible dans une hiérarchie de classes ou vers une interface satisfaite est une assignation de sous-typage normale et ne nécessite pas une syntaxe de cast dédiée.
|
|
|
|
```text
|
|
Dog dog = ...;
|
|
Animal animal = dog;
|
|
Serializable serializable = dog;
|
|
```
|
|
|
|
## 24.4 Downcast et raffinement — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
Le mécanisme canonique de downcast V1 est le test `is` suivi du raffinement de type dans le scope positif.
|
|
|
|
```text
|
|
Animal animal = ...;
|
|
|
|
if (animal is Dog) {
|
|
// animal est raffiné en Dog ici.
|
|
}
|
|
```
|
|
|
|
Lorsqu'un test du type runtime exact est nécessaire, `instanceof` est utilisé.
|
|
|
|
Saselang n'introduit pas pour le moment de syntaxe générale concurrente telle que `(Dog)value`, `value as Dog` ou `cast<Dog>(value)`. Une telle opération ne pourra être ajoutée que si un besoin distinct de `is`/`instanceof` + refinement est démontré et si son contrat d'échec est explicite.
|
|
|
|
## 24.5 API numérique du Core — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
Les conversions numériques sont exposées comme membres standard des primitives définis par le Core. Les noms de méthodes ne sont pas des mots-clés du langage.
|
|
|
|
Le compilateur connaît les règles nécessaires pour typer, vérifier, constant-fold et abaisser ces opérations vers Sase IR, mais l'inventaire exhaustif de la surface API appartient au Core.
|
|
|
|
L'introduction de `Fault` supprime l'obligation historique de créer une variante `try... -> Result<T,NumericConversionError>` uniquement parce qu'une conversion directe peut échouer.
|
|
|
|
Principe de nommage V1 :
|
|
|
|
```text
|
|
toTarget()
|
|
conversion exacte
|
|
totale si tout le domaine source est représentable
|
|
sinon valeur directe + faults NumericConversionFault
|
|
|
|
roundToTarget()
|
|
perte de précision / arrondi explicitement accepté
|
|
peut fault si une autre précondition reste violée, par exemple le domaine fini destination
|
|
|
|
saturateToTarget()
|
|
saturation explicite lorsque la politique de plage est le seul ajustement demandé
|
|
|
|
saturatingRoundToTarget()
|
|
arrondi + saturation explicitement annoncés lorsque les deux sont nécessaires
|
|
|
|
wrapToTarget()
|
|
wrapping entier explicite
|
|
```
|
|
|
|
Une opération n'existe que si elle apporte une sémantique observable différente d'une autre forme disponible pour la paire source/destination.
|
|
|
|
Le Core ne duplique pas mécaniquement :
|
|
|
|
```text
|
|
toTarget()
|
|
tryToTarget()
|
|
```
|
|
|
|
lorsque la seule différence serait que la seconde transporte le même échec dans `Result`.
|
|
|
|
Une API spécialisée peut toujours choisir volontairement `Result` si l'échec doit devenir une donnée normale du domaine, mais cela ne fait pas partie de la matrice canonique des conversions primitives.
|
|
|
|
Règle de composition : deux opérations Core ne sont fusionnées dans un même nom que si leur séparation en opérations successives modifierait la sémantique, perdrait de l'information ou empêcherait d'exprimer le même contrat.
|
|
|
|
Lorsqu'une composition existante est strictement équivalente, aucun alias combiné n'est ajouté au Core.
|
|
|
|
## 24.6 Entier -> entier — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
Si toutes les valeurs source sont représentables exactement dans la destination :
|
|
|
|
```text
|
|
toTarget() -> Target
|
|
```
|
|
|
|
est total et ne déclare aucun `NumericConversionFault` lié à la plage.
|
|
|
|
Lorsque certaines valeurs source ne sont pas représentables :
|
|
|
|
```text
|
|
toTarget() -> Target
|
|
faults NumericConversionFault
|
|
```
|
|
|
|
avec `OutOfRange` lorsque la valeur courante n'entre pas dans le domaine destination.
|
|
|
|
Les politiques alternatives restent explicites :
|
|
|
|
```text
|
|
saturateToTarget()
|
|
wrapToTarget()
|
|
```
|
|
|
|
Elles ne sont présentes que lorsqu'elles peuvent produire un résultat différent de `toTarget()` pour cette paire.
|
|
|
|
Aucun wrapping ni saturation n'est implicite.
|
|
|
|
## 24.7 Entier -> flottant — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
`toFloatXX()` exige une représentation exacte de la valeur entière.
|
|
|
|
```text
|
|
toFloatXX() -> floatXX
|
|
faults NumericConversionFault
|
|
```
|
|
|
|
n'a une clause `faults` que lorsque certaines valeurs source peuvent être inexactes ou hors du domaine fini destination.
|
|
|
|
`roundToFloatXX()` accepte explicitement l'arrondi canonique `nearest, ties to even` :
|
|
|
|
```text
|
|
roundToFloatXX() -> floatXX
|
|
```
|
|
|
|
Il peut encore produire `OutOfRange` si une valeur entière finie dépasse le domaine fini de la destination.
|
|
|
|
Lorsque l'arrondi et la saturation doivent être annoncés ensemble :
|
|
|
|
```text
|
|
saturatingRoundToFloatXX()
|
|
```
|
|
|
|
borne une magnitude finie trop grande au plus grand fini de même signe puis applique la précision destination.
|
|
|
|
Il n'existe pas de `wrapToFloatXX()`.
|
|
|
|
## 24.8 `float -> integer` — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
La conversion stricte utilise désormais directement :
|
|
|
|
```text
|
|
toIntXX() -> intXX
|
|
faults NumericConversionFault
|
|
|
|
toUintXX() -> uintXX
|
|
faults NumericConversionFault
|
|
```
|
|
|
|
Elle réussit uniquement si la valeur source est :
|
|
|
|
```text
|
|
finie
|
|
mathématiquement entière
|
|
dans le domaine de la destination
|
|
exactement représentable comme entier destination
|
|
```
|
|
|
|
Sinon le fault porte la catégorie appropriée.
|
|
|
|
Les politiques mathématiques de traitement de la partie fractionnaire restent des opérations séparées :
|
|
|
|
```text
|
|
floor()
|
|
ceil()
|
|
round()
|
|
truncate()
|
|
```
|
|
|
|
Elles se composent avec la conversion :
|
|
|
|
```text
|
|
value::floor()::toInt32()
|
|
value::ceil()::toInt32()
|
|
value::round()::toInt32()
|
|
value::truncate()::toInt32()
|
|
```
|
|
|
|
Saselang n'introduit pas les alias redondants `floorToInt32()`, `ceilToInt32()`, `roundToInt32()` ou `truncateToInt32()` lorsque ces compositions possèdent exactement la même sémantique.
|
|
|
|
Les politiques de dépassement de domaine se composent de la même façon :
|
|
|
|
```text
|
|
value::floor()::saturateToInt32()
|
|
value::round()::wrapToInt32()
|
|
```
|
|
|
|
Pour `float -> integer` :
|
|
|
|
```text
|
|
saturateToTarget()
|
|
exige encore une valeur finie et mathématiquement entière
|
|
faults NotFinite / NotIntegral si nécessaire
|
|
sature uniquement la plage
|
|
|
|
wrapToTarget()
|
|
exige encore une valeur finie et mathématiquement entière
|
|
faults NotFinite / NotIntegral si nécessaire
|
|
applique le wrapping modulo 2^N à l'entier mathématique fini
|
|
```
|
|
|
|
Une méthode combinée reste admise uniquement lorsqu'une décomposition changerait le contrat ou perdrait l'information nécessaire.
|
|
|
|
## 24.9 `float -> float`, valeurs IEEE spéciales — V1 REQUIS — FIGÉ
|
|
|
|
Toute conversion de valeur flottante préserve les catégories sémantiques suivantes lorsque la destination est un type flottant Saselang :
|
|
|
|
```text
|
|
NaN -> NaN
|
|
+Infinity -> +Infinity
|
|
-Infinity -> -Infinity
|
|
+0 -> +0
|
|
-0 -> -0
|
|
```
|
|
|
|
Pour `NaN`, la conversion garantit uniquement que la destination reste `NaN`.
|
|
|
|
Elle ne garantit pas lors d'une conversion de valeur :
|
|
|
|
```text
|
|
payload NaN
|
|
quiet/signaling bit
|
|
signe du NaN
|
|
représentation binaire exacte
|
|
```
|
|
|
|
Ces propriétés relèvent d'un contrat binaire distinct.
|
|
|
|
Pour une réduction de format :
|
|
|
|
```text
|
|
toFloatXX()
|
|
exige l'exactitude de la valeur sémantique
|
|
faults Inexact ou OutOfRange pour une valeur finie si nécessaire
|
|
|
|
roundToFloatXX()
|
|
accepte l'arrondi canonique
|
|
faults OutOfRange si une valeur finie dépasse le domaine fini destination
|
|
|
|
saturatingRoundToFloatXX()
|
|
accepte l'arrondi canonique
|
|
sature une valeur finie hors domaine vers +/-Target::Max
|
|
```
|
|
|
|
`NaN` et les infinities sont déjà représentables dans les formats flottants Saselang et ne sont donc pas saturés.
|
|
|
|
## 24.10 `NumericConversionFault` — V1 REQUIS — NOM DE TRAVAIL / CODES FIGÉS
|
|
|
|
`NumericConversionFault` est retenu comme nom de travail du `Fault` Core utilisé par les conversions numériques directes dont les préconditions runtime peuvent échouer.
|
|
|
|
```text
|
|
NumericConversionFault extends Fault
|
|
```
|
|
|
|
Les catégories sémantiques V1 sont :
|
|
|
|
```text
|
|
NotFinite
|
|
NotIntegral
|
|
OutOfRange
|
|
Inexact
|
|
```
|
|
|
|
Sens :
|
|
|
|
```text
|
|
NotFinite
|
|
NaN ou +/-Infinity lorsqu'une valeur finie est requise
|
|
|
|
NotIntegral
|
|
float -> integer alors que la valeur n'est pas mathématiquement entière
|
|
|
|
OutOfRange
|
|
valeur mathématique hors du domaine de la destination
|
|
|
|
Inexact
|
|
valeur dans le domaine destination mais non représentable exactement
|
|
alors que l'opération exige l'exactitude
|
|
```
|
|
|
|
`NumericConversionFault` reste volontairement minimal. Il n'ajoute pas automatiquement :
|
|
|
|
```text
|
|
sourceType
|
|
targetType
|
|
sourceValue
|
|
timestamp
|
|
backend
|
|
roundingMode
|
|
```
|
|
|
|
au-delà de l'état commun fourni par `Error`/`Fault`.
|
|
|
|
## 24.11 Réduction anti-doublon par paire — V1 REQUIS — FIGÉ
|
|
|
|
La matrice examine chaque paire `Source -> Target` et n'expose que les opérations dont le comportement peut réellement être distingué sur le domaine source.
|
|
|
|
Lorsqu'une opération directe est totale pour toute la paire, elle ne déclare aucun fault inutile.
|
|
|
|
Lorsqu'une politique `saturate` ou `wrap` ne peut jamais différer de la conversion exacte sur cette paire, elle est absente.
|
|
|
|
La disparition des variantes `try...` ne modifie pas cette règle de non-redondance ; elle supprime seulement les duplications qui ne différaient que par le canal d'échec `ResultError` versus valeur directe.
|
|
|
|
## 24.12 Disponibilité Core et target — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
Les conversions fondamentales de la matrice sont des capacités Core obligatoires dès lors que les types source et destination sont supportés par le target.
|
|
|
|
L'absence d'une instruction matérielle native ne justifie pas l'absence d'une conversion si une émulation logicielle conforme est raisonnablement possible.
|
|
|
|
Un target réduit peut ne pas supporter un type fondamental donné. Dans ce cas l'indisponibilité porte sur le type/capacité fondamentale, pas sur une sélection arbitraire de ses méthodes de conversion.
|
|
|
|
Voir également le chapitre 40.
|
|
|
|
## 24.13 Matrice exhaustive — ANNEXE NORMATIVE EN COURS DE GEL
|
|
|
|
L'inventaire source -> destination des opérations de conversion est maintenu séparément afin d'éviter les oublis, doublons et incohérences.
|
|
|
|
Voir :
|
|
|
|
```text
|
|
annexes/A-numeric-conversions.md
|
|
```
|
|
|
|
L'annexe liste les possibilités sémantiquement distinctes après suppression des variantes `try...` purement liées à l'ancien canal `ResultError`.
|
|
|
|
---
|