Quelques conseils d'optimisation
Prévenir les erreurs d'incompatibilité :
Les différentes versions de Vertel ont souvent quelques incompatibilités entre elles, et les versions 1.xx et 2.xx n'ont aucune fonction en commun. Il est donc plus que conseillé de vérifiez que la librairie est correcte avant de continer votre programme, de cette façon si l'utilisateur change la librairie pour en mettre une plus ancienne il sera averti de son erreur. Voici par exemple comment procéder pour la version 2.00 beta 8, pour laquelle "e_vers" retourne "2.00 ß8" :
local test
vertel("e_vers","/","e_retr","test")
if GetType(test)="NONE":{"0"}->test
if test[1]=/="2.00 ß8" then (ce
=/= représente le signe "different")
text "Erreur : La version 2.00 beta 8 de Vertel est requise"
stop
endif
En mettant une protection de ce type au début de vos programme, vous vous éviterez (ainsi qu'à moi même :)) les mails d'utilisateurs qui se pleignent de ne pas pouvoir faire fonctionner vos créations.
Nombres / Chaines :
Les nombres et les chaines sont traités séparéments
dans la lib. Cela signifie que vous pouvez regrouper toutes les chaines au début
dune fonction et tous les nombres à la fin, ou bien linverse.
Lordre na pas dimportance entre les nombres et les chaines,
par contre entre 2 arguments dun même type lordre est évidemment
à respecter.
Plus clairement, la fonction "d_zoom","normal","zoomed",50,70
peut sécrire : "d_zoom",50,70,"normal","zoomed"
ou même "d_zoom",50,"normal",70,"zoomed".
Limiter les appels :
Essayez de minimiser le nombre d'appels de Vertel. En effet
tout ce qui est traité dans la librairie est bien plus rapide que du
Ti-Basic. Cette commande :
For t,10,40,10 : vertel("d_crcv",80,50,t,t) :
Endfor
est beaucoup plus lente que celle-ci :
vertel("d_crcv",80,50,10,10,"/","d_crcv",80,50,20,20,"/","d_crcv",80,50,30,30,"/","d_crcv",80,50,40,40)
En effet la 1ere fonction appelle quatre fois Vertel, tandis que la 2eme ne l'appelle quune seule fois. Voici un comparatif :
Note : De toute façon,
dans un cas comme dans l'autre ce n'est pas la meilleure optimisation possible.
Il est encore plus rapide d'utiliser deux listes en argument et d'écrire
:
vertel("d_crcv",80,50,{10,20,30,40},{10,20,30,40}).
Voyez le paragraphe
"Utiliser des listes en argument" pour plus d'informations.
Appeler Vertel avec une liste au lieu des arguments :
Vous pouvez assez simplement passer des listes de forme {"d_line",0,0,159,99} comme argument de Vertel, il suffit pour cela de quelques petites modifications. Le plus simple est d'utiliser un sous-programme qui convertit la liste et lance Vertel avec :
define vlist(liste)=prgm
expr("vertel("&mid(string(liste),2,dim(string(liste))-2)&")")
endprgm
Il ne vous reste plus qu'à lancer vlist({"d_line",0,0,159,99}).
Attention : Ceci ne fonctionne pas si votre appel de librairie contient des listes d'arguments, car le Ti-Basic ne supporte pas les "listes de listes", c'est à dire ce genre d'écriture : {"d_pixl",{10,20},{10,20}}.
Utiliser des listes en argument :
Utiliser des listes en argument est la
meilleure façon d'optimiser, car cela prends peu de place dans le programme
et est traité très rapidement par Vertel. Il y a tout de même
certaines choses à savoir avant d'utiliser les listes correctement.
Premièrement les listes obligent une fonction à se rappeller sur
elle-même, en lisant une à une les valeurs de la liste. Mais les
arguments simples, eux, ne varieront pas. Par exemple, écrire ceci :
vertel("d_pixl",{10,20,30,40,50,60},25)
tracera 6 pixels, tous à la coordonnée y=25, mais aux coordonnées
x 10,20,30,40,50 et 60.
Il faut savoir que Vertel s'arrête
de lire dès qu'elle arrive à la fin d'une des listes passées
en argument. Ecrire :
vertel("d_pixl",{10,20},{5,10,15,20,25,30})
ne tracera que 2 pixels, car il n'y a que 2 élements dans la 1ere liste.
Les 4 élements "en trop" dans la seconde liste sont donc ignorés.
Vertel s'arrête également
de lire les listes au moindre changement dans le type d'un argument. Cela signifie
que :
vertel("d_pict",{"pic1","pic2",27,"pic4"},20,20)
n'appelera que 2 fichiers PIC, car le 3eme élement de la liste n'est
pas du même type que les précedents, et la lecture s'arrête
donc immédiatement.
Dernière chose : l'utilisation
de listes fonctionne aussi pour la commande. Ce type d'appel est valide :
vertel({"d_recp","d_recv"},29,40,139,60,{1,49})
Deux rectangles sont dessinés aux mêmes coordonnées, un
plein en blanc pour effacer le fond puis un vide en noir avec des coins arrondis.
Utilisation de 'seq' pour effectuer des commandes très rapidement :
Pour effectuer très rapidement plusieurs fois la même
fonction, la commande seq() peut se réveler très utile. Si vous
avez la flemme d'ouvrir votre notice, voici exactement ce qu'elle fait :
seq(calcul,variable,min,max[,pas])
Ceci retourne une liste, dans laquelle 'calcul' a été effectué pour 'variable' de min à max, avec un pas de 'pas'. En clair, c'est à peu près la même chose que si vous aviez fait une fonction comme ceci :
{}->list
for variable,min,max,pas
expression->list[dim(list)+1]
endfor
Sauf que seq est évidement BEAUCOUP plus rapide que
cette pseudo-fonction, et qu'elle renvoie une valeur, au lieu de la stoquer
comme ici dans la variable list. Voici un exemple
simple :
seq(a*2,a,0,5) retourne {0,2,4,6,8,10}
car le calcul a*2 a été effectué
pour a de 0 à
5
Maintenant imaginez que vous vouliez tracer une série
de pixels horizontalement (même si la commande d_line
est ici beaucoup plus pratique), vous pouvez utiliser ceci :
vertel("drw_pixl",seq(a,a,0,159),49)
La commande seq() renvoie une liste {0,1,2,3,4,...,159}, et
donc 160 pixels sont tracés, presque instantanément. Comparez
l'efficacité de seq() par rapport à une boucle for :
seq() peut être très pratique dans beaucoup d'autre cas, à vous de trouver lesquels.
Accelerer l'utilisation de listes en argument :
Les indirections internes peuvent servir à accelerer l'utilisation des listes en argument. En effet l'inconvegnant majeur de ce procédé est que le TiOS doit analyser la liste avant de pouvoir lancer la lib avec. Il est possible d'empecher cette analyse pour la confier à Vertel, et ainsi gagner un temps précieux.
Imaginons un éditeur hexadecimal. La liste des octets
de votre fichier est stoqué dans la variable 'hexa'. À la fin
du programme, pour stoquer cette liste dans votre fichier, il semble logique
de faire :
vertel("v_writ","fichier",0,hexa)
Mais vous pouvez également utiliser :
vertel("v_vrit","fichier",0,"#hexa")
De cette manière le TiOS n'aura pas à analyser la variable hexa, qu'il considèrera comme une chaine. Notez que cela vous oblige à stoquer votre liste dans une variable, alors que l'utilisation 'normale' des listes permet de les placer directement en argument. Cette technique est donc utile uniquement si votre listé était déjà stoqué dans une variable avant l'appel de Vertel. C'est à vous de voir quelle est la méthode la plus rapide pour votre programme.
Optimisations en un seul appel (1) :
Nous avons vu qu'il fallait généralement
limiter le nombre d'appels de Vertel, mais parfois cela est impossible, notament
lors de l'utilisation de variables. Par
exemple, ces deux appels ne peuvent pas être réduis à un
seul :
vertel("v_size","vertel","/","e_retr","var")
vertel("t_draw","Taille de la lib : "&string(var[1]),2,2,1)
Pourquoi ? Et bien parceque le TiOS doit analyser la variable var pour pouvoir la convertir avec string(), et enfin la placer au bout de la chaine à afficher. Et cela doit être fait avant l'appel de Vertel, il faut donc 'passer la main' au TiOS, ce qui oblige à quitter Vertel entre le moment ou la variable est créée et le moment où elle est utilisée.
Optimisations en un seul appel (2) :
Nous avons vu dans le paragraphe précedent
que certaines suites d'appels ne peuvent pas être réduites, mais
en utilisant les indirections internes cela devient generalement possible.
vertel("v_list","/","e_retr","var")
vertel("v_list",var,"/","e_retr","var")
Le premier appel place dans var la
liste des dossiers présents sur la Ti. Le deuxième appel utilise
la liste var placée en argument, et retourne
donc une liste de tous les fichiers contenus dans la Ti (la fonction
lit chaque dossier grâce à la liste placée en argument).
Nous avons vu pourquoi 'coller' ces deux appels poserait problème : le
TiOS doit analyser la variable var avant de lancer
Vertel, et comme elle n'est créée que pendant l'appel, elle serait
considérée comme vide par Vertel, et le deuxième v_list
se ferait sur une liste vide.
La technique consiste donc à empecher le TiOS d'analyser cette variable,
et de demander à Vertel de le faire au dernier moment. On utilise alors
une indirection interne :
vertel("v_list","/","e_retr","var","/","v_list","#var","/","e_retr","var")
Remarquez le "#var"
: de cette façon le TiOS n'analyse pas la variable var,
puisqu'il considère que c'est une chaine quelconque. Par contre, quand
Vertel effectuera le deuxième v_list,
elle lira cette variable var, qui aura subit des
modifications grâce à la première utilisation de la fonction.
Ce n'est donc qu'une question de priorités, pour résumer l'utilisation
d'une indirection interne sert à retarder l'analyse de la variable var,
et ainsi pouvoir la modifier dans le même appel de lib, pourvu que ce
soit avant que Vertel ait réellement besoin de la 'lire'.
Affecter tous les fichiers d'un dossier avec les commandes de variables :
Oui, vous pouvez facilement executer une commande pour tous les fichiers d'un dossier, grâce à la gestion de liste. Vous voulez par exemple avoir le type de tous les fichiers du dossier main :
vertel("v_list","main",0,1,"/","e_retr","var","/","v_type","#var","/","e_retr","var")
La variable var contiendra alors une liste correspondant aux types de chaque fichiers : v_list établit une liste des fichiers du dossier main puis retourne une liste. On lance avec v_type avec cette liste (et une indirection, car la variable a été créée pendant l'appel).
Note : Il est nécessaire d'utiliser le 2eme argument de v_list, car le dossier dans lequel on veut faire l'oppération n'est pas forcément le même que le dossier courant, et il faut donc dans ce cas le préciser, en passant en argument des noms de variable de type "dossier\fichier". L'argument de v_list permet justement de retourner les noms de fichier sous cette forme.
Utiliser le retour de liste interne :
Prenons comme exemple un appel qui cache
tous les dossiers de la calculatrice :
vertel("v_list","/","e_retr","var","/","v_hide","#var",1)
À la fin de l'appel vous n'aurez
probablement plus besoin de la variable "var". Vous pouvez alors utiliser
un retour de liste interne, c'est à dire que la liste retournée
ne sera utilisable que jusqu'à la fin de l'appel. L'avantage est que
vous n'avez pas à déclarer cette variable en local ou à
la supprimer après l'appel. La variable interne porte le nom "©".
Voici comment l'utiliser, avec le même exemple :
vertel("v_list","/","e_retr","/","v_hide","#©",1)
L'appel est plus court, notement parceque e_retr sans argument retourne par défaut la variable interne, donc il n'est pas nécessaire de la préciser. D'autre part vous n'avez pas à supprimer de variable à la fin. Notez que la variable interne s'utilise exactement de la même manière qu'une variable classique, donc l'indirection est nécessaire pour analyser la variable au dernier moment.
Voici un autre exemple : comment afficher
le numéro de la version à l'écran, en un seul appel, sans
utiliser de variables du programme :
vertel("e_vers","/","e_retr","/","t_draw","#©",999,20,1)
Modifier les variables locales d'un autre programme :
Oui, c'est possible, grâce à la fonction s_locl qui, comme expliqué dans le descriptif, peut obliger vertel à lire les variables locales d'un programme qui a lancé celui ou vous vous trouvez actuellement. Voici un exemple :
define localmod()=prgm
local x
define modify()=prgm
vertel("v_list","/","s_locl",1,"/","e_retr","x")
endprgm
clrio
disp "Dossiers :"
pause x
endprgm
Ce programme lance modify(), qui est
défini comme sous-programme. modify() lance vertel pour obtenir la liste
des dossiers, puis remonte "d'un programme en arrière" pour
les variables locales : "s_locl",1.
Il retourne ensuite la liste des dossiers dans la variable x, mais comme nous
sommes revenu en arrière, il s'agit de la variable x du programme précedent,
c'est à dire localmod(). modify() a donc modifié la valeur d'une
variable locale qui a été définie dans un autre programme.
Ceci peut servir par exemple pour remplacer les fonctions : en effet beaucoup
d'instructions y sont interdites, et leur seul avantage est de 'retourner' une
valeur, c'est à dire pouvoir la donner au programme lanceur sans utiliser
de variable globale qui fasse le 'saut' entre les deux. Grâce à
Vertel, vous pouvez directement relier le sous-programme à son lanceur,
et modifier ses variables.
Vous pouvez aussi copier une variable d'un sous-programme à son lanceur grâce à la fonction v_load : chargez dans la mémoire de vertel les données à renvoyer, revenez en arrière puis utilisez e_retr pour les récupérer dans un des programmes lanceurs.
Dernière chose : Voici comment contourner la protection qui empeche d'utiliser certaines instructions dans les "func:endfunc", en utilisant s_locl :
define enter(v)=prgm
local c
request "Entrez un mot ",c
vertel("v_load",c,"/","s_locl",1,"/","e_retr",v)
endprgm
En utilisant un programme de ce type, vous pouvez remplacer les fonctions : appellez enter("var"), où var est une variable locale, et le sous programme enter stoquera le mot entré dans cette variable. Le seul inconvegnant est que la variable est sous forme de liste, mais il suffit de faire var[1]->var pour y remédier.
Note 1 : Si vous revenez d'un rang en arrière par rapport au programme lanceur, vertel considère alors les variables locales comme globales.
Note 2 : L'argument num de s_locl indique le nombre de rangs à 'remonter', à partir du programme qui appelle vertel. Si vous utilisez vertel("s_locl",{1,1}), vous ne remontez pas de deux dossiers en arrière (1+1) mais d'un seul (deux fois le même retour en arrière depuis le programme qui appelle la lib).
Note 3 : Le dossier local est restauré à la fin de l'appel de la lib. vertel("s_locl",1) sans autres fonctions n'a donc aucun effet : cela change le dossier local actif puis le restaure aussitôt puisque la librairie a fini son execution.
Types de fichiers :
Voici quelques types de fichiers, utiles a connaitre pour certaines commandes de type "v_" :
45 : STR
217 : LIST ou MAT
220 : PRGM ou FUNC
221 : DATA
222 : GDB
223 : PIC
224 : TEXT
243 : ASM
248 : OTH (extension personnelle)
Messages d'erreur de la version Developper :
Vertel Developper renvoie des messages d'erreur dans la Status line en cas d'arguments erronés. Ils sont tous précedés de 'Arg' ou 'Fnc'. Les erreurs de type 'Arg' sont des erreurs d'arguments, et 'Fnc' d'utilisation de fonction. Voici la signification des différents messages :
Arg : Argument invalide : Un des
arguments donnés n'est ni une liste, ni une chaine, ni un entier.
Arg : Changement LIST NUM : Un élement non-numérique a
été trouvé dans une liste numérique.
Arg : Changement LIST STR : Un élement non-chaine a été
trouvé dans une liste de chaines.
Arg : Coordonnées invalides : Vous utilisez une
fonction graphique avec des coordonnées invalides.
Arg : Indirection invalide : Vous faite une indirection
sur une variable qui n'existe pas.
Arg : LIST invalide : Une des listes placée
en argument a un 1er element non-numérique et non-chaine.
Arg : Trop d'arguments LIST : Impossible de placer plus
de 10 listes en argument pour une seule fonction.
Arg : Trop d'arguments NUM : Impossible de placer plus
de 10 nombres en argument pour une seule fonction.
Arg : Trop d'arguments STR : Impossible de placer plus
de 10 chaines en argument pour une seule fonction.
Fnc : 2 < taille < 65520 : Un fichier ne peut pas
faire moins de 2 octets ou plus de 65520 octets.
Fnc : Creation de variable impossible : Impossible de
créer une variable (erreur rare).
Fnc : Erreur de lecture de variable : Impossible de lire
une variable, elle a probablement été enregistrée de manière
incorrecte.
Fnc : Octet invalide : Vous essayez d'écrire dans
un fichier à un octet qui n'appartient pas au fichier.
Fnc : Redimentionnement impossible : Pas assez de RAM
pour augmenter la taille de la liste de retour et y placer de nouvelles données.
Fnc : Suppression impossible : La fonction v_delt
n'est pas parvenue à supprimer une variable, probablement mal enregistrée
en mémoire.