Produire une trace d'exécution
Si un as un morceau de code, on peut souhaiter savoir dans quel ordre les instructions sont exécutées.
Principe
On veut accomplir 2 éléments principaux :
- indiquer quelles lignes de code s'exécutent dans quel ordre
- indiquer les effets de chaque ligne de code
- indiquer la pile d'appels
- Exemple simple
- Avec boucle
- Avec fonction
- Réseau
- Valider une trace
- Procédure pour faire un exercice
Trace
On aura la trace suivante :
ligne exécutée | effet | pile d'appels |
---|---|---|
val a = 3 + 4 | a: 7 | main |
val b = a * 2 | a: 7, b: 14 | main |
println("salut " + b) | a: 7, b: 14, affiche "salut 14" | main |
Dans le cas d'une séquence d'instructions, on peut voir que les instructions sont exécutées dans l'ordre de lecture du code. Simple!
Pour voir le code des tableaux markdown, ICI.
Note : pour chaque page de ce site, tu peux cliquer sur le bouton Éditer cette page en bas pour voir le code markdown.
Code
fun main() {
for (i in 1..3){
if (i % 2 == 0) {
println("c'est pair " + i)
}
else {
println("ah ben ah ben, c'est impair " + i)
}
}
}
On voit que :
- on n'indique que les lignes qui s'exécutent en vrai
- certaines lignes s'exécutent plusieurs fois, c'est le principe de la boucle!
- on appelle ce cheminement le flot de contrôle
Trace
ligne exécutée | effet | pile d'appels |
---|---|---|
for (i in 1..3) | i parcourt l'interval 1, 2, 3 | main |
if (i % 2 == 0) | i: 1 i%2 vaut 1 | main |
println("ah ben ah ben, c'est impair " + i) | i: 1 affiche "ah ben ah ben, c'est impair 1" | main |
for (i in 1..3) | i rendu à 2 | main |
if (i % 2 == 0) | i: 2 i%2 vaut 0 | main |
println("c'est pair " + i) | i: 2 affiche "c'est pair 2" | main |
for (i in 1..3) | i rendu à 3 | main |
if (i % 2 == 0) | i: 3 i%2 vaut 1 | main |
println("ah ben ah ben, c'est impair " + i) | i: 3 affiche "ah ben ah ben, c'est impair 3" | main |
Code
fun ma_fonction(a : Int, b: Int) : Int {
val c = a + b
return c
}
fun main() {
var mavariable = 3
var tavariable = 5
var z = ma_fonction(mavariable, tavariable)
var y = ma_fonction(4, 9)
print("z vaut " + z + " et y vaut " + y)
}
S'il y a des fonctions dans le code, la pile d'appels permet d'indiquer :
- quand on entre dans le code d'une autre fonction
- quelles sont les fonctions qui sont encore actives
Trace
ligne exécutée | effet | pile d'appels |
---|---|---|
var mavariable = 3 | mavariable: 3 | main |
var tavariable = 5 | mavariable: 3 tavariable: 5 | main |
var z = ma_fonction(mavariable, tavariable) | mavariable: 3 tavariable: 5 appelle ma_fonction avec 3→a et 5→b | main |
val c = a + b | a: 3 b: 5 c: 8 | ma_fonction main |
return c | a: 3 b: 5 c: 8, retourne 8 | ma_fonction main |
var z = ma_fonction(mavariable, tavariable) | mavariable: 3 tavariable: 5 z: 8 | main |
var y = ma_fonction(4, 9) | mavariable: 3 tavariable: 5 z: 8 appelle ma_fonction avec 4→a et 9→b | main |
val c = a + b | a: 4 b: 9 c: 13 | ma_fonction main |
return c | a: 4 b: 9 c: 13 retourne 13 | ma_fonction main |
var y = ma_fonction(4, 9) | mavariable: 3 tavariable: 5 z: 8 y:13 | main |
println("z vaut " + z + " et y vaut " + y) | mavariable: 3 tavariable: 5 z: 8 y = 13 affiche "z vaut 8 et y vaut 13" | main |
On veut faire la trace d'exécution lorsqu'on ouvre l'application client, en assumant que le serveur roule et que tout se passe bien.
Code client
interface Service {
@POST("plus100")
fun plus100(@Body nombre: Int): Call<Int>
}
object retrofit {
val service: Service = retrofit2.Retrofit.Builder()
.addConverterFactory(retrofit2.converter.gson.GsonConverterFactory.create())
.baseUrl("http://10.0.2.2:8080/")
.build()
.create(Service::class.java)
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
retrofit.service.plus100(42).enqueue(object : retrofit2.Callback<Int> {
override fun onResponse(call: retrofit2.Call<Int>, response: retrofit2.Response<Int>) {
if (response.isSuccessful) {
Toast.makeText(this@MainActivity, response.body()!!.toString(), Toast.LENGTH_LONG).show()
}
else{
Toast.makeText(this@MainActivity, "Error", Toast.LENGTH_LONG).show()
}
}
override fun onFailure(call: retrofit2.Call<Int>, t: Throwable) {
Log.i("Heille", t.message.toString())
}
})
}
}
Code serveur
@Controller
public class Controlleur {
@PostMapping("/plus100")
public @ResponseBody Integer plus100(@RequestBody Integer nombre) {
return nombre + 100;
}
}
Trace
ligne exécutée | effet | pile d'appels |
---|---|---|
super.onCreate(savedInstanceState) | appelle la fonction onCreate de la classe parente | onCreate |
setContentView(R.layout.activity_main) | affiche le layout activity_main.xml | onCreate |
retrofit.service.plus100(42).enqueue(object : retrofit2.Callback<Int> { | appelle la méthode plus100 avec 42 -> nombre et lance en asynchrone la requête POST http://10.0.2.2:8080/plus100/ avec "42" comme corps | onCreate |
return nombre + 100; | retourne 142 et renvoie une réponse HTTP avec "142" comme corps et le code 200 Ok | plus100 |
if (response.isSuccessful) { | vérifie si la réponse response reçue du serveur est un succès | onResponse |
Toast.makeText(this@MainActivity, response.body()!!.toString(), Toast.LENGTH_LONG).show() | affiche "142" dans un Toast | onResponse |
Afin de valider ta trace, tu vas utiliser le débogueur de ton IDE préféré.
- place un point d'arrêt sur la première ligne qui s'exécute
- lance l'exécution en mode débogage
- saute d'une ligne en une ligne pour voir si ta trace est correcte
Si tu te rends à la fin de l'exécution et que toutes tes valeurs étaient bonnes, tu as bien compris ce que fait le code.
- ouvre ton repo d'exercices sur github.com
- crée un fichier avec le nom suggéré dans l'exercice en appuyant sur le bouton + puis Create new file
- dès que tu indiques un nom qui finit en .md on aura l'onglet code et l'onglet preview
- copie le code de l'exercice dans le fichier, tu peux utiliser un bloc de kotlin pour avoir la syntaxe colorée. Par exemple :
```kotlin
fun main() {
val a = 3 + 4
val b = a * 2
println("salut " + b)
}
```
- ajoute la trace d'exécution en dessous du code dans un tableau markdown. Par exemple :
| ligne exécutée | effet | pile d'appels |
|-----------------|-----------------------------------|---------------|
| val a = 3 + 4 | a: 7 | __main__ |
- Tu peux utiliser des balises html
</br>
pour faire un retour de ligne, par exemple dans la pile d'appels. - Crée-toi un projet kotlin ou Android pour valider ta trace en utilisant le débogueur.