# 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(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(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 — DIRECTION FIGÉE 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. Principe de nommage : ```text toTarget() conversion exacte et totale tryToTarget() conversion exacte pour la valeur courante, récupérable si impossible roundToTarget() perte de précision explicitement acceptée, conversion totale tryRoundToTarget() perte de précision explicitement acceptée, mais conversion pouvant échouer saturateToTarget() saturation explicite lorsqu'aucun arrondi supplémentaire n'est nécessaire saturatingRoundToTarget() arrondi + saturation explicitement annoncés wrapToTarget() wrapping entier explicite ``` Une forme n'existe que si elle apporte une sémantique observable différente d'une autre forme déjà disponible pour la paire source/destination. Ainsi, lorsqu'un `toTarget()` exact et total existe, les variantes `tryToTarget()`, `saturateToTarget()` ou `wrapToTarget()` qui produiraient exactement le même résultat pour tout le domaine source sont absentes. 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 `float -> integer` — V1 REQUIS — DIRECTION FIGÉE Un flottant ne possède jamais un simple `toIntXX()` ou `toUintXX()`. La conversion exacte stricte utilise : ```text tryToIntXX() tryToUintXX() ``` Elle réussit uniquement si la valeur source est finie, mathématiquement entière et représentable exactement dans le type destination. Sinon elle retourne `Result::Err(NumericConversionError(...))`. Les politiques mathématiques de traitement de la partie fractionnaire restent des opérations Core séparées : ```text floor() ceil() round() truncate() ``` Elles se composent avec la conversion : ```text value::floor()::tryToInt32() value::ceil()::tryToInt32() value::round()::tryToInt32() value::truncate()::tryToInt32() ``` Saselang n'introduit donc pas les alias redondants `tryFloorToInt32()`, `tryCeilToInt32()`, `tryRoundToInt32()` ou `tryTruncateToInt32()` lorsque ces compositions possèdent exactement la même sémantique. Les politiques de dépassement de domaine suivent la même règle : ```text value::floor()::trySaturateToInt32() value::round()::tryWrapToInt32() ``` `trySaturateToIntXX()` exige une valeur finie et mathématiquement entière, puis sature aux bornes du type destination. Les échecs qui ne relèvent pas de la plage, par exemple `NaN`, une infinité ou une valeur fractionnaire, restent des `NumericConversionError`. `tryWrapToIntXX()` exige également une valeur finie et mathématiquement entière, puis applique le wrapping entier modulo `2^N` défini par Saselang. Une méthode combinée reste admise lorsqu'une décomposition changerait le contrat ou perdrait l'information nécessaire. C'est notamment le cas de `saturatingRoundToFloat32()` pour certains narrowings flottants : un `roundToFloat32()` séparé pourrait échouer avant que la saturation ne puisse être appliquée. Aucun comportement de conversion ne dépend d'un profil, d'un linter ou d'un backend. ## 24.7 `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 éventuel contrat binaire distinct ; `bitcast` ne peut les préserver que lorsque ses propres contraintes, notamment de taille, sont satisfaites. `tryToFloatXX()` traite `NaN` et les infinités comme des valeurs sémantiques représentables du type flottant destination. Le mot « exact » désigne ici l'exactitude de la valeur sémantique Saselang, pas l'identité bit-à-bit d'un payload NaN. Pour une valeur finie : ```text tryToFloatXX() exige une représentation exacte tryRoundToFloatXX() accepte l'arrondi canonique refuse une valeur finie hors domaine fini destination saturatingRoundToFloatXX() accepte l'arrondi canonique sature une valeur finie hors domaine vers +/-Target::Max ``` Les infinités ne sont pas saturées puisqu'elles sont déjà des valeurs représentables du format flottant destination. ## 24.8 `NumericConversionError` — V1 REQUIS — NOM DE TRAVAIL / CODES FIGÉS `NumericConversionError` est retenu comme nom de travail du `ResultError` Core utilisé par les conversions numériques récupérables. 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 ``` `NumericConversionError` reste volontairement généraliste et minimal. Il n'ajoute pas automatiquement : ```text sourceType targetType sourceValue timestamp backend roundingMode ``` au-delà de l'état commun fourni par `ResultError`. Le nom concret et la représentation numérique interne des codes pourront encore être ajustés avant stabilisation publique, mais les catégories sémantiques ci-dessus font partie du contrat V1. ## 24.9 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. Ainsi, pour une paire `float -> integer` dont toutes les valeurs finies mathématiquement entières sont déjà dans le domaine signé destination, `trySaturateToTarget()` et `tryWrapToTarget()` seraient des doublons de `tryToTarget()` et n'existent pas. Pour une destination non signée, les valeurs négatives suffisent généralement à rendre les politiques checked, saturating et wrapping distinctes. La matrice exhaustive en annexe est normative sur ce point. ## 24.10 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.11 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 doit lister le maximum de possibilités sémantiquement distinctes avant réduction finale de l'API Core. ---