Files
saselang-bible/chapters/024-casts-et-conversions.md
2026-09-13 10:20:16 +02:00

11 KiB

24. Casts et conversions

24.1 Principe général — V1 REQUIS — FIGÉ EN PRINCIPE

Saselang distingue explicitement :

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.

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.

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.

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 :

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 :

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 :

toTarget() -> Target

est total et ne déclare aucun NumericConversionFault lié à la plage.

Lorsque certaines valeurs source ne sont pas représentables :

toTarget() -> Target
    faults NumericConversionFault

avec OutOfRange lorsque la valeur courante n'entre pas dans le domaine destination.

Les politiques alternatives restent explicites :

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.

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 :

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 :

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 :

toIntXX() -> intXX
    faults NumericConversionFault

toUintXX() -> uintXX
    faults NumericConversionFault

Elle réussit uniquement si la valeur source est :

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 :

floor()
ceil()
round()
truncate()

Elles se composent avec la conversion :

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 :

value::floor()::saturateToInt32()
value::round()::wrapToInt32()

Pour float -> integer :

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 :

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 :

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 :

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.

NumericConversionFault extends Fault

Les catégories sémantiques V1 sont :

NotFinite
NotIntegral
OutOfRange
Inexact

Sens :

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 :

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 :

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.