Variables et types
Créer des variables, choisir un type numérique qui déborde comme vous l'attendez, activer OPTION EXPLICIT, partager l'état avec GLOBAL, et exposer un réglage dans l'Inspecteur.
En un mot#
Une variable existe dès que vous l'affectez. Elle contient n'importe quelle
valeur, jusqu'à ce que vous lui donniez un type avec AS ; à partir de là,
toute valeur rangée dedans est convertie dans ce type. OPTION EXPLICIT rend
les déclarations obligatoires, et GLOBAL partage une variable avec vos
fonctions.
Les variables implicites#
<name> = <value>
Console(Str(count)) ' 0 : lue avant sa première affectation
count = 5
Console(Str(count)) ' 5
x = 1
x = "maintenant du texte"
Console(x) ' maintenant du texte
- La première affectation crée la variable. Il n'y a ni
DIMniVARpour une simple valeur. - Une variable lue avant sa première affectation vaut 0.
- Une variable sans type contient n'importe quoi : un nombre, puis une chaîne, puis de nouveau un nombre. Ses nombres sont ceux de JavaScript (virgule flottante sur 64 bits).
⚠️ Un nom que le programme n'affecte jamais n'est pas une variable.
total = lives + 1, avec lives affecté nulle part, compile. Le programme
s'arrête ensuite sur cette ligne avec lives is not defined. C'est ainsi
qu'apparaît un nom mal orthographié.
⚠️ Une variable $ lue avant sa première affectation vaut 0 elle aussi, et
non une chaîne vide. Donnez-lui d'abord une valeur.
Console("[" + title$ + "]") ' [0], pas []
title$ = "Héros"Les sigils#
Un nom de variable peut finir par un sigil.
| Sigil | Sens classique |
|---|---|
$ | texte |
# | nombre décimal |
% | entier |
& | entier long |
Ce que fait un sigil#
- Il choisit la valeur de départ d'une variable déclarée sans valeur :
GLOBAL a, b$donne0et"". - Il choisit ce qu'attend
READd'une ligneDATA: du texte pour$, un nombre décimal pour#, un entier sinon. - Il type un champ d'enregistrement. Dans un
TYPE, un champ sans sigil niASest un entier. Voir Enregistrements et méthodes. - Il choisit la sorte d'un réglage exposé. Voir
@exposeplus bas. - Sur un appel de commande, il doit correspondre au résultat.
Str$(12)est accepté ; un$sur une commande qui rend un nombre est refusé.
v$ = Val$("12")
Val does not return text: drop the $ sigil
Ce que ne fait pas un sigil#
Un sigil ne convertit rien. Pour convertir, donnez un type à la variable avec
AS.
n% = 2.7
Console(Str(n%)) ' 2.7 : le % n'arrondit pas
t$ = 5
Console(Str(t$ + 1)) ' 6 : le $ ne fait pas du texte
Deux noms qui ne diffèrent que par leur sigil#
obj et obj$ sont deux variables. C'est ce qu'attendent les programmes
classiques.
obj = 1
obj$ = "mesh" + Str(obj) + ".obj"
Console(Str(obj) + " " + obj$) ' 1 mesh1.obj
⚠️ Un champ d'enregistrement à sigil perd son type dès que le même nom
apparaît sans le sigil ailleurs dans le programme : une variable speed, ou
s.speed pour un champ déclaré speed#. Le champ devient alors un entier :
2.5 est rangé en 2, et un texte arrête le programme. Donnez à un tel champ
un nom à lui, ou déclarez-le avec AS (speed AS float), qui n'a pas de sigil
à perdre.
TYPE Ship
hp
speed#
name$
ENDTYPE
s AS Ship
s.hp = 2.7
s.speed# = 2.5
s.name$ = "Ada"
Console(Str(s.hp) + " " + Str(s.speed#) + " " + s.name$) ' 2 2.5 AdaLes variables typées : AS#
[GLOBAL | LOCAL] <name> AS <type> [= <value>]
[GLOBAL | LOCAL] <name> AS <type>[<size>[, <size> ...]] [= [<value>, ...]]
lives AS integer = 3
speed AS float = 2.5
title AS string = "Héros"
hits AS ubyte
hits = 250
hits = hits + 10
Console(Str(hits)) ' 4 : 260 a fait le tour après 255
- Sans
= <valeur>, un nombre part de 0, une chaîne de"", une poignée deNULL. Certains noms de type exigent la valeur : voir les ⚠️ du tableau plus bas. - Le type agit à chaque rangement d'une valeur : avec
=, avec+=,-=,*=,/=, et avecINCetDEC. - Le calcul entre deux rangements n'est pas typé.
h / 2est calculé en pleine précision ; seul le rangement le convertit. - Le nom d'une variable typée ne porte pas de sigil.
name$ AS stringcompile, mais le programme ne démarre pas. Écrivezname AS string. - La forme tableau
AS <type>[<taille>]est traitée dans Les collections, etAS <type enregistrement>dans Enregistrements et méthodes.
h AS integer = 7
h = h / 2
Console(Str(h)) ' 3 : 3.5 est rangé en 3
q = h / 2
Console(Str(q)) ' 1.5 : q n'a pas de type
Tous les types#
| Type | S'écrit aussi | Plage | Notes |
|---|---|---|---|
int8 | byte ⚠️, b | −128 … 127 | |
uint8 | ubyte, ascii, a ⚠️ | 0 … 255 | |
int16 | word, short, w | −32 768 … 32 767 | |
uint16 | uword, ushort, unicode, u ⚠️, c ⚠️ | 0 … 65 535 | |
int32 | integer, int ⚠️, long, i, l ⚠️ | −2 147 483 648 … 2 147 483 647 | long fait 32 bits |
uint32 | uint, uinteger, dword | 0 … 4 294 967 295 | |
int64 | quad, q | −2⁶³ … 2⁶³ − 1 | voir 64 bits plus bas |
uint64 | uquad | 0 … 2⁶⁴ − 1 | voir 64 bits plus bas |
float32 | float, single, f ⚠️ | environ 7 chiffres significatifs | float fait 32 bits |
float64 | double, d | environ 15 chiffres significatifs | la précision d'un nombre sans type |
string ⚠️ | s | texte | toute valeur est transformée en texte |
handle | pointer ⚠️ | une référence (@variable) | NULL par défaut |
taskhandle | job | une tâche en cours | NULL par défaut |
Les noms de type sont insensibles à la casse. Les noms d'une lettre sont les suffixes de PureBasic.
⚠️ Les noms marqués ⚠️ exigent une valeur. Écrits seuls (x AS byte,
x AS string), ils perdent leur type, parce que le compilateur les lit comme
le début d'un nom de commande du catalogue (ByteLen, StringToBase64…). La
variable se comporte alors comme une variable sans type qui part de 0. Écrivez
x AS byte = 0 et x AS string = "", ou prenez un nom sans ⚠️.
a AS byte
a = 300
Console(Str(a)) ' 300 : aucun type n'a été appliqué
b AS int8
b = 300
Console(Str(b)) ' 44
Comment une valeur est convertie#
| Rangée dans | Règle | Exemple |
|---|---|---|
| un type entier | les décimales tombent (vers zéro) | 7.9 → 7, -7.9 → -7 |
| un type entier | hors plage, la valeur fait le tour | int8 : 127 + 1 → -128 ; uint16 : -1 → 65535 |
| un type entier | un texte fait de chiffres est lu | "12" → 12 |
| un type entier | tout autre texte arrête le programme | "abc", "1.5" → BASIC integer requires an integral value |
| un type entier | l'infini arrête le programme | 1 / 0 → BASIC integer requires a finite value |
float32 | arrondie au flottant 32 bits le plus proche | 0.1 → 0.10000000149011612 |
string | toute valeur devient du texte | 42 → "42" |
n AS integer = 7.9
m AS integer = -7.9
k AS integer = "12"
w AS word = 40000
Console(Str(n) + " " + Str(m) + " " + Str(k + 1) + " " + Str(w)) ' 7 -7 13 -25536
⚠️ Un compteur de FOR typé ne fait pas le tour. FOR b = 250 TO 260 avec
b AS uint8 compte jusqu'à 260 et finit à 261. Le type agit de nouveau à la
prochaine affectation ordinaire.
⚠️ float fait 32 bits#
Dans aukimi, float et single sont des float32, comme dans AGK. Une
valeur comme 0.1 ne se range pas exactement, et Str montre tous les
chiffres de ce qui est rangé.
price AS float = 0.1
Console(Str(price)) ' 0.10000000149011612
exact AS double = 0.1
Console(Str(exact)) ' 0.1
Console(Str(price, 2)) ' 0.10
Prenez double quand les décimales doivent s'afficher proprement, ou donnez à
Str un nombre de décimales. Une variable sans type a déjà la double
précision.
⚠️ long fait 32 bits#
long est un int32, comme le .l de PureBasic. Le Long 64 bits de
Visual Basic s'écrit ici quad (int64).
big AS long = 3000000000
Console(Str(big)) ' -1294967296
Les entiers 64 bits#
int64 et uint64 contiennent des valeurs 64 bits exactes. Ce sont des
nombres d'une sorte à part, qui ne se mélangent qu'entre eux.
Ce qui marche :
counter AS int64 = 5
counter = counter + 1
counter += 10
INC counter
Console(Str(counter)) ' 17
huge AS int64 = "9223372036854775807"
Console(Str(huge)) ' 9223372036854775807
five AS int64 = 5
IF counter > five THEN Console("plus grand")
| Forme | Marche ? |
|---|---|
big = big + n, big += n, -=, *=, /=, INC, DEC | oui |
big2 = big + other64 (rien que des valeurs 64 bits) | oui |
big = 5, big = "123" | oui |
big > 4, big < 10 | oui |
⚠️ y = big + 1 (le résultat n'est pas une variable 64 bits) | s'arrête : Cannot mix BigInt and other types |
⚠️ other AS int64 = big * 3 | s'arrête : même message |
⚠️ IF big = 5 | jamais vrai : comparez avec une autre variable 64 bits |
⚠️ big = big * 2 + 1 | résultat faux : calculé comme big * (2 + 1) ; écrivez big *= 2 puis big += 1 |
| ⚠️ un littéral au-delà de 9 007 199 254 740 991 | perd ses derniers chiffres : écrivez-le en texte, "9223372036854775807" |
La division entière de valeurs 64 bits laisse tomber les décimales : big /= 4
garde la partie entière. Ne prenez les types 64 bits que si 32 bits sont
vraiment trop petits.
Les littéraux de chaque type#
| Type | Écrire | Note |
|---|---|---|
| types entiers | 42, -7, 0x1F, 0c17, %1010 | une valeur décimale est coupée : 7.9 → 7 |
| 64 bits | 42, ou "9223372036854775807" | en texte au-delà de 2⁵³ |
float, double | 2.5, .5, 1.25e2 | |
string | "texte" | un nombre est transformé en texte |
handle | @variable, NULL |
TRUE et FALSE ne sont pas des nombres : voir
Constantes et opérateurs.
Les suffixes de type de PureBasic : .f, .i, .s…#
<name>.<suffix> = <value>
speed.f = 1.5
speed = speed * 2
count.i = 7.9
label.s = "x"
Console(Str(speed) + " " + Str(count) + " " + label) ' 3 7 x
- Le premier
nom.suffixedéclare la variable avec ce type, comme si vous écrivieznom AS <type>. Les lignes suivantes peuvent laisser tomber le suffixe. - Les suffixes sont les noms d'une lettre du tableau plus haut :
b a w u c l i q f d s. - Une variable qui est déjà un enregistrement, ou un objet du catalogue comme
un sprite, garde ses propres champs :
s.xsur un sprite n'est pas un suffixe.
⚠️ c est un uint16 sur une variable et dans une liste, mais un int32 sur
un champ d'enregistrement.
OPTION EXPLICIT#
OPTION EXPLICIT [' comment]
OPTION EXPLICIT
GLOBAL lives AS integer = 3
GLOBAL score = 0
GLOBAL name$ = "Ada"
DIM grid(2)
FUNCTION Hit(damage)
LOCAL rest = lives - damage
lives = rest
ENDFUNCTION lives
Hit(1)
score = score + 10
grid(1) = score
Console(name$ + " " + Str(lives) + " " + Str(grid(1))) ' Ada 2 10
OPTION EXPLICIT est désactivé par défaut, pour que les programmes importés
compilent encore. Une fois activé, tout nom dans lequel vous écrivez doit
être déclaré d'abord.
OPTION EXPLICIT
score = 1
OPTION EXPLICIT requires a declaration for variable: score
- Il est seul sur sa ligne. Seul un commentaire
'peut le suivre ;OPTION EXPLICIT // noteest refusé. - Il vaut pour tout le programme, fichiers inclus compris, où que soit la ligne.
- Toutes les démos d'aukimi l'utilisent.
Ce qui doit être déclaré#
| Écrit par | Exemple |
|---|---|
| une affectation | score = 1, grid(1) = 4, hero.hp = 3 (le premier nom) |
| un compteur de FOR | FOR i = 1 TO 10 |
INC / DEC | INC score |
READ | READ level |
Ce qui compte comme déclaration#
| Déclaration | Exemple |
|---|---|
GLOBAL | GLOBAL score, GLOBAL score = 0, GLOBAL a, b$ |
LOCAL, dans une FUNCTION | LOCAL rest = 0 |
AS | lives AS integer, hero AS Player |
| un suffixe PureBasic | speed.f = 1.5 |
DIM | DIM grid(10) |
NewList, NewMap | NewList names.s() |
| un paramètre de FUNCTION | FUNCTION Hit(damage) |
une variable de CATCH | CATCH problem$ |
⚠️ OPTION EXPLICIT contrôle les noms où vous écrivez, pas ceux que vous
lisez. Un nom mal orthographié à droite du = compile quand même, et arrête
le programme quand la ligne s'exécute.
OPTION EXPLICIT
GLOBAL total = 0
total = totl + 1 ' compile ; s'arrête à l'exécution : totl is not definedGLOBAL et LOCAL#
GLOBAL <name> [= <value>]
GLOBAL <name> AS <type> [= <value>]
GLOBAL <name>, <name> [, <name> ...]
LOCAL <name> [= <value>]
LOCAL <name> AS <type> [= <value>]
LOCAL <name>, <name> [, <name> ...]
GLOBAL DIM, LOCAL DIM, GLOBAL NewList et GLOBAL NewMap déclarent des
collections de la même façon. Define et Protected de PureBasic sont
acceptés comme LOCAL.
| Mot-clé | Où | Effet |
|---|---|---|
GLOBAL | partout, même dans une FUNCTION | une seule variable pour tout le programme, vue par toutes les fonctions |
LOCAL | dans une FUNCTION | une variable propre à cet appel ; elle masque une variable du programme de même nom |
FUNCTION Setup()
GLOBAL best = 100
ENDFUNCTION
Setup()
Console(Str(best)) ' 100
⚠️ Donnez une valeur à un GLOBAL seul. GLOBAL hits tout seul part vide,
pas de 0, et hits + 1 donne alors NaN. La forme en liste part de 0 (ou de
"").
GLOBAL hits
Console(Str(hits)) ' undefined, pas 0
GLOBAL misses = 0
Console(Str(misses)) ' 0
GLOBAL a, b$
Console(Str(a) + "[" + b$ + "]") ' 0[]
⚠️ LOCAL a sa place dans une FUNCTION. Au premier niveau du programme,
une variable LOCAL affectée de nouveau plus loin casse le programme : il ne
démarre pas. Utilisez GLOBAL ou AS à cet endroit. Il en va de même pour
Define.
LOCAL lives = 3
lives = 2La portée#
Un bloc n'est pas une portée#
Une variable affectée pour la première fois dans un IF, un FOR, un WHILE
ou un SELECT appartient au programme. Elle existe encore après le bloc. Le
compteur du FOR aussi, un pas après la fin.
IF 1 = 1
found = 42
ENDIF
Console(Str(found)) ' 42
FOR i = 1 TO 3
NEXT
Console(Str(i)) ' 4
Les fonctions#
Dans une FUNCTION :
- Les paramètres et les noms
LOCALappartiennent à l'appel. - Un nom
GLOBAL, ou un nom que le programme affecte au-dessus de la fonction, est la variable du programme. La fonction la lit et l'écrit. - Tout autre nom affecté dans la fonction est une nouvelle variable locale.
score = 0
FUNCTION AddPoint()
score = score + 1
ENDFUNCTION
AddPoint()
AddPoint()
Console(Str(score)) ' 2
FUNCTION Bump()
LOCAL score = 99
score = score + 1
ENDFUNCTION score
score = 1
Console(Str(Bump()) + " " + Str(score)) ' 100 1
⚠️ L'ordre des lignes compte. Si le programme n'affecte score qu'en
dessous de la fonction, la fonction se fait son propre score, et le lire
d'abord arrête le programme.
FUNCTION AddPoint()
score = score + 1 ' une nouvelle locale : score n'est affecté que plus bas
ENDFUNCTION
score = 0
AddPoint() ' s'arrête : Cannot access 'score' before initialization
⚠️ Avec DO … LOOP, les fonctions ne voient pas les variables ordinaires#
Dans un programme avec une boucle d'image, les lignes de préparation au-dessus
de DO s'exécutent dans la fonction propre de la boucle. Une FUNCTION ne voit
pas les variables qu'elles créent, même pour les lire seulement.
score = 10
FUNCTION Show()
Console(Str(score))
ENDFUNCTION
DO
Show() ' s'arrête : score is not defined
Sync()
LOOP
La solution est GLOBAL. Une variable GLOBAL est déclarée pour tout le
programme, quelle que soit sa forme.
GLOBAL score = 10
FUNCTION Show()
Console(Str(score))
ENDFUNCTION
DO
Show() ' 10, puis 11, 12…
score = score + 1
Sync()
LOOP
Les constantes ont la même limite : voir Constantes et opérateurs.
Déclarez avec
GLOBALtoute valeur qu'une fonction partage avec le programme. Cela marche quelle que soit la forme du programme, et l'ordre des lignes cesse de compter.
@expose : un réglage dans l'Inspecteur#
' @expose [range(<min>, <max>)]
[GLOBAL] <name>[<sigil>] [AS <type>] = <value>
Un commentaire @expose sur la ligne juste au-dessus d'une affectation de
premier niveau fait de cette variable un réglage. L'Inspecteur l'affiche,
et la valeur qu'on y choisit remplace celle écrite dans le code au démarrage
du programme.
' @expose range(0, 20)
speed# = 5.5
' @expose
title$ = "Héros"
' @expose
lives = 3
' @expose
godMode = FALSE
Console(title$ + " " + Str(speed#) + " " + Str(lives) + " " + Str(godMode)) ' Héros 5.5 3 0
| La déclaration | Le réglage | Lu avec |
|---|---|---|
un nom $, ou AS string | texte | PropString |
un nom #, ou AS float | nombre décimal | Prop |
TRUE ou FALSE | marche/arrêt, rangé en 1 ou 0 | PropInteger |
| tout le reste | nombre entier | PropInteger |
- Le réglage porte le nom de la variable, sans son sigil :
speed#devientspeed. range(a, b), ou simplement(a, b), fixe les bornes affichées dans l'Inspecteur.- Le marqueur peut s'écrire avec
',REM,//ou un accent grave. - Sous
OPTION EXPLICIT, exposez une déclaration :GLOBAL lives = 3, ouspeed AS float = 2.5.
⚠️ Un réglage décimal exige # ou AS float. zoom AS double = 1.5 et
ratio = 0.75 deviennent des réglages entiers : ils partent de 1 et de 0.
⚠️ L'affectation doit être au premier niveau. Dans une FUNCTION ou un TYPE, le
marqueur est refusé : @expose must be followed by a top-level assignment (name = value).
Vous venez d'un autre BASIC#
| Vous attendez | Dans aukimi |
|---|---|
x% = 2.7 range 2 | range 2.7 : utilisez x AS integer |
float fait 64 bits | float fait 32 bits : utilisez double |
Long fait 64 bits (Visual Basic) | long fait 32 bits : utilisez quad |
DIM x AS INTEGER | x AS integer : DIM sans taille compile, mais le programme ne démarre pas |
x.f (PureBasic) | accepté |
Define x = 1 au premier niveau (PureBasic) | utilisez GLOBAL x = 1 |
une variable $ lue avant usage vaut "" | elle vaut 0 : affectez-la d'abord |
OPTION EXPLICIT contrôle tous les noms | il contrôle les noms où vous écrivez |