Validation test works with numerical values but not strings

Asked

Viewed 95 times

4

My inheritance code works normal, what I wanted to do is if the nome and the pseudonimo are null the code would stop, the code only stops running when idade, altura or peso sane null.

import 'dart:io';
 
main() {

  var humano = Humano();
  var pessoa = Pessoa();

  stdout.write("Digite o seu nome: ");
  pessoa.nome = stdin.readLineSync();
  if (pessoa.nome == null) return;
  stdout.write("Digite o seu pseudônimo: ");
  pessoa.pseudonimo = stdin.readLineSync();
  if (pessoa.pseudonimo == null) return;
  stdout.write("Digite a sua idade: ");
  pessoa.idade = int.tryParse(stdin.readLineSync());
  if (pessoa.idade == null) return;
  stdout.write("\n");

  stdout.write("Digite o seu peso: ");
  humano.peso = double.tryParse(stdin.readLineSync());
  if (humano.peso == null) return;
  stdout.write("Digite o sua altura: ");
   humano.altura = double.tryParse(stdin.readLineSync());
  if (humano.altura == null) return;
  stdout.write("\n");

  print("Nome: ${pessoa.nome}");
  print("Idade: ${pessoa.idade}"); 
  print("Pseudônimo: ${pessoa.pseudonimo}");
  print("Altura: ${humano.altura}cm");
  print("Peso: ${humano.peso}kg");

}

class Humano {

  double peso;
  double altura;

  Humano({this.peso, this.altura});

}

class Pessoa extends Humano {

  String nome;
  String pseudonimo;
  int idade;

  Pessoa({this.nome, this.pseudonimo, this.idade});
  
}

1 answer

2


First of all, let’s notice some things.

Two objects are not necessary when one belongs to a subclass of the other

According to what you put in the question, the class Pessoa inherits (extends) the class Humano - moreover, I do not know if this class is really necessary.

If, in fact, it inherits, then it is not necessary for you to create an object of Pessoa and an object of Humano to be able to use the members of each, since the first should have the members of the second!

What seems to be happening is that you’re not calling the superclass builder Pessoa (the class Humano). That is, although you inherit from the class, you do not ask her to process the data that is appropriate to her.

For this, you use the commando super, which (in several languages) serves exactly to call the superclass constructor (mother-class) one-class.

class Humano {

  double peso;
  double altura;

  Humano({this.peso, this.altura});
}

class Pessoa extends Humano {

  String nome;
  String pseudonimo;
  int idade;

  Pessoa({double peso, double altura, this.nome, this.pseudonimo, this.idade})
    : super(peso: peso, altura: altura); 
}

I mean, I take the parameters peso and altura and step to the constructor of the class that will handle them, ie the constructor of the [super]class Humano!

Getting the data first and creating the object later

Another thing we could modify, is that instead of you creating the "empty" object and filling in your fields as you ask the user - which is a bit like what you sometimes do with the structs in C - in my opinion, it might look better if you got this data first, and then passed it to the class constructor Pessoa:

main() {
  double peso, altura;
  String nome, pseudonimo;
  int idade;

  stdout.write("Digite o seu nome: ");
  nome = stdin.readLineSync();
  
  stdout.write("Digite o seu pseudônimo: ");
  pseudonimo = stdin.readLineSync();
  
  stdout.write("Digite a sua idade: ");
  idade = int.tryParse(stdin.readLineSync());

  stdout.write("Digite o seu peso: ");
  peso = double.tryParse(stdin.readLineSync());
  
  stdout.write("Digite a sua altura: ");
  altura = double.tryParse(stdin.readLineSync());
  
  stdout.write("\n");

  var pessoa = new Pessoa(
    peso: peso,
    altura: altura,
    nome: nome,
    pseudonimo: pseudonimo,
    idade: idade
  );
  
  print("Nome: ${pessoa.nome}");
  print("Idade: ${pessoa.idade}");
  print("Pseudônimo: ${pessoa.pseudonimo}");
  print("Altura: ${pessoa.altura}cm");
  print("Peso: ${pessoa.peso}kg");
}

Because, this way, you will both be making the proper use of the constructor, as well as leaving the code a little more "organized", through the next suggestion.

Validating data within class

Asking for the data first and creating the object later allows you to validate the data in the class itself!

From my perspective, I think this is also the best thing to do, because the class will be responsible for establishing the "rules", in the same way as in a kind of MVC structure, the layer Model is responsible for business rules. However, at the end of the day, I will have a small disadvantage in the use of this method.

But let’s solve the problem!

Solving the real problem

When you use the function stdin.readLineSync, she will return one string! So if you don’t type anything, instead of returning null, she will return a string empty ("").

Already the static method int.tryParse, when trying to convert the value you were given, your return may be an integer (int), or null, the last when the conversion was not successful. Likewise, the static method double.tryParse (only instead of int, returns a double).

And with that, we figured out why the null for idade, altura and peso work: because, when the user does not type anything, the string empty is converted by these methods to null!

Therefore, to validate the data that are strings, we should use the properties that serve exactly to know if a string is empty or not. It is they: String#isEmpty and String#isNotEmpty.

So now in order to do the validation in the class, we can choose to use manual techniques in this way:

class Humano {

  double peso;
  double altura;

  Humano({this.peso, this.altura}) {
    if (peso == null || altura == null) {
      throw new Exception("os campos 'peso' e 'altura' não devem ser nulos!");
    }
  }
}

class Pessoa extends Humano {

  String nome;
  String pseudonimo;
  int idade;

  Pessoa({double peso, double altura, this.nome, this.pseudonimo, this.idade})
    : super(peso: peso, altura: altura)
  {
    if (nome.isEmpty || pseudonimo.isEmpty || idade == null) {
      throw new Exception("os campos 'nome', 'pseudonimo' e 'idade' não devem ser nulos ou vazios!");
    }
  } 
}

Or, we can choose to use commands provided by the language itself, such as the command assert, about which you can learn more in that post!

With it, the code could get even smaller:

class Humano {

  double peso;
  double altura;

  Humano({this.peso, this.altura})
    : assert(peso != null && altura != null,
             "os campos 'peso' e 'altura' não devem ser nulos!");
}

class Pessoa extends Humano {

  String nome;
  String pseudonimo;
  int idade;

  Pessoa({double peso, double altura, this.nome, this.pseudonimo, this.idade})
    : assert(nome.isNotEmpty && pseudonimo.isNotEmpty && idade != null,
             "os campos 'nome', 'pseudonimo' e 'idade' não devem ser nulos ou vazios!"),
      super(peso: peso, altura: altura);
}

OBS.: when you use other boot commands along with the super, with this syntax, always put the super last! Otherwise it will generate an error!

In both codes, we make sure that:

  • The class Pessoa ensure that data from nome and pseudonimo are not empty, and the data of idade not be null;
  • The class Humano ensure that data from peso and altura not be null.

But in the second case, you have to pay attention to what is said in that answer - about activating the command assert - because if it is deactivated, the validation will not take effect!


After all, your code should look like this:

Form with manual validation

import "dart:io";

main() {
  double peso, altura;
  String nome, pseudonimo;
  int idade;

  stdout.write("Digite o seu nome: ");
  nome = stdin.readLineSync();
  
  stdout.write("Digite o seu pseudônimo: ");
  pseudonimo = stdin.readLineSync();
  
  stdout.write("Digite a sua idade: ");
  idade = int.tryParse(stdin.readLineSync());

  stdout.write("Digite o seu peso: ");
  peso = double.tryParse(stdin.readLineSync());
  
  stdout.write("Digite a sua altura: ");
  altura = double.tryParse(stdin.readLineSync());
  
  stdout.write("\n");

  var pessoa = new Pessoa(
    peso: peso,
    altura: altura,
    nome: nome,
    pseudonimo: pseudonimo,
    idade: idade
  );
  
  print("Nome: ${pessoa.nome}");
  print("Idade: ${pessoa.idade}");
  print("Pseudônimo: ${pessoa.pseudonimo}");
  print("Altura: ${pessoa.altura}cm");
  print("Peso: ${pessoa.peso}kg");
}

class Humano {

  double peso;
  double altura;

  Humano({this.peso, this.altura}) {
    if (peso == null || altura == null) {
      throw new Exception("os campos 'peso' e 'altura' não devem ser nulos!");
    }
  }
}

class Pessoa extends Humano {

  String nome;
  String pseudonimo;
  int idade;

  Pessoa({double peso, double altura, this.nome, this.pseudonimo, this.idade})
    : super(peso: peso, altura: altura)
  {
    if (nome.isEmpty || pseudonimo.isEmpty || idade == null) {
      throw new Exception("os campos 'nome', 'pseudonimo' e 'idade' não devem ser nulos ou vazios!");
    }
  } 
}

Form with validation with assert

import "dart:io";

main() {
  double peso, altura;
  String nome, pseudonimo;
  int idade;

  stdout.write("Digite o seu nome: ");
  nome = stdin.readLineSync();
  
  stdout.write("Digite o seu pseudônimo: ");
  pseudonimo = stdin.readLineSync();
  
  stdout.write("Digite a sua idade: ");
  idade = int.tryParse(stdin.readLineSync());
  
  stdout.write("\n");

  stdout.write("Digite o seu peso: ");
  peso = double.tryParse(stdin.readLineSync());
  
  stdout.write("Digite o sua altura: ");
  altura = double.tryParse(stdin.readLineSync());
  
  stdout.write("\n");

  var pessoa = new Pessoa(
    peso: peso,
    altura: altura,
    nome: nome,
    pseudonimo: pseudonimo,
    idade: idade
  );
  
  print("Nome: ${pessoa.nome}");
  print("Idade: ${pessoa.idade}");
  print("Pseudônimo: ${pessoa.pseudonimo}");
  print("Altura: ${pessoa.altura}cm");
  print("Peso: ${pessoa.peso}kg");
}

class Humano {

  double peso;
  double altura;

  Humano({this.peso, this.altura})
    : assert(peso != null && altura != null,
             "os campos 'peso' e 'altura' não devem ser nulos!");
}

class Pessoa extends Humano {

  String nome;
  String pseudonimo;
  int idade;

  Pessoa({double peso, double altura, this.nome, this.pseudonimo, this.idade})
    : assert(nome.isNotEmpty && pseudonimo.isNotEmpty && idade != null,
             "os campos 'nome', 'pseudonimo' e 'idade' não devem ser nulos ou vazios!"),
      super(peso: peso, altura: altura);
}

Completion

One point, however, which makes the programme act differently, is that validation will only be done once all the data have been completed. That is, the user will not have an immediate return on the validity of that inconsistent data that he provided.

Despite this, now, the operation of the program will be in the form that (I think) is expected and still with a code, in my opinion, a little better separated and "organized"!

Another thing also that I could have talked about in the answer, but I chose not to, is about the new type system with null-Safety of Dart. He would change much the way you would write this code! Only, since it is not yet mandatory, so I did not want to cover it now. But, who knows, in the future, I can add something about this! :)

  • Interesting your explanation, thank you.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.