sexta-feira, 11 de novembro de 2011

Input parameter cannot be assigned

Uma das caracteristicas mais importantes em um programador é a sua capacidade de organização lógica, apesar de que raciocionio rápido, eficiência, velocidade também são fundamentais.  Por natureza todo programador é organizado, gosta de manter seu código limpo, comentado e claro, de forma que outros da equipe possam entender rapidamente o que foi feito, e por alguma necessidade, interferir realizando uma manutenção.  Estou enganado?

Pois é aqui buscamos duas coisas, uma é incentivar os desenvolvedores a documentarem e organizarem seu código, e a segunda é resolver a questão do erro Input parameter cannot be assigned.

'Melhores Práticas'

É uma pretensão gigante de minha parte criar aqui uma lista de melhores práticas de desenvolvimento, mesmo porque cada pessoa tem um perfil, cada empresa um padrão, ou seja, vamos direto ao ponto, que é como documentar os parametros utilizados para transferir informações de um lugar para outro.

Aprendi que existem dois tipos de pessoas no mundo, aquelas que fazem de tudo para esconder o que sabem e o que fizeram, e aquelas que sente prazer em falar o que sabe pra todo mundo.  Infelizmente o segundo tipo acaba se dando mal em algumas situações, experiência própria.  O primeiro tipo pensa o seguinte, vou programar de forma que somente eu possa entender o programa, assim, fico garantido porque ninguem mexe comigo, rs...., pode ser também uma questão de extrema desorganização, falta de tempo, ou seja, uma série de desculpas para não deixar a "coisa clara". Vamos ao exemplo, citando um amigo ficticio que chamaremos de Mario, cujo perfil é, mais ou menos, do primeiro tipo de pessoa.

Certo dia, o Mario chegou pra trabalhar em sua empresa e tinha que programar uma rotina complexa em uma procedure, algo relacionado a faturamento, impostos, ..., e como tinha que passar um montão de parametros, escreveu algo semelhante a:

parm(&invc, &xkpt, &sbtrr, &isn, &kkrg, &aaiins, &inss, &ir, &sbtstr, &opt1, &opt2, &opt3);

Nada muito complexo, sob a ótica do Mario, mesmo porque a procedure tratava todos esses parâmetros, com um extenso código de1200 linhas, mas que ele tinha tudo na cabeça, e claro, conhecia linha por linha desse procedimento e sabia exatamente o que tinha que passar de informação e o que tinha de receber da procedure. Já viu algo assim? pois é um dia eu vi e reforçou o que eu já fazia antes, que era programar de forma clara, mesmo porque levei dois dias para interpretar o que o Mario queria dizer com cada uma das variáveis malucas criadas.

Nem vou dizer a respeito de comentários de código, sub-rotinas documentadas e coisas do gênero, vamos apenas buscar melhorar a lista de parametros. Desta forma, acredito, na minha humilde e singela opinião, que uma prática melhor seria programar algo assim:

parm(

   &invc,    // indice de variacao

   &xkpt,    // pre-calculo final

   &sbtrr,   // valor da substituicao trib.

   &isn,     // valor do imposto recebido

   &kkrg,    // valor interno de calculo

   &aaiis,   // previa do iss 

   &iss,     // imposto iss calculado

   &ir,      // imposto ir calculado

   &sbtstr// valor final da subst. trib

   &opt1,    // opcao de calculo com ir

   &opt2,    // opcao de calculo com iss

   &opt3     // opcao de calculo com subst.

   );


'Input parameter cannot be assigned'

Vamos ao erro que motivou o post, Input parameter cannot be assigned, que quer dizer o seguinte, todo parametro recebido no parm não pode ser atribuido um valor diferente.  É causado toda vez que um parâmetro é envolvido em uma operação que altera seu valor, como no exemplo a seguir.

parm(&a, &b, &c);



&a = &a+1

&b = &b*&a

&c = &s+&b

Desta forma, se não se informa o contrário, todo parâmetro é de entrada, e não aceita alterações em seus valores.  E nessa lógica, se existe o conceito de parametro de entrada, temos também o conceito de parametros de saída e de entrada e saída.  E é exatamente para isso que servem os flags in:, out:, inout: providos pelo Gx.

O mais interessante é que parametros do tipo inout: tanto podem receber informações quanto devolver valores calculados, ou seja, a declaração do parametro desse tipo é suficiente para remover a mensagem Input parameter cannot be assigned.


Ja pensou então se definissemos no parm do Mario quais os parametros que seriam fornecidos a procedure, e quais a procedure nos devolveriam? Teriamos um código melhor mesmo, porque não precisariamos ligar toda hora pro Mario para perguntar o que é tal coisa.


parm(

      in: &invc,   // indice de variacao

     out: &xkpt,   // pre-calculo final

     out: &sbtrr// valor da substituicao trib.

      in: &isn,    // valor do imposto recebido

      in: &kkrg,   // valor interno de calculo

   inout: &aaiis// previa do iss 

     out: &iss,    // imposto iss calculado

     out: &ir,     // imposto ir calculado

     out: &sbtstr, // valor final da subst. trib

      in: &opt1,   // opcao de calculo com ir

      in: &opt2,   // opcao de calculo com iss

      in: &opt3    // opcao de calculo com subst.

   );

Enfim, parametros de saída são aqueles que em uma chamada com Call podem receber valores.


Tenho usado, na maioria das vezes, esse tipo de programação, e salvo a própria complexidade das rotinas programadas, acredito que a clareza e a documentação do código sejam práticas fundamentais para o sucesso nos projetos.

Agora muito cuidado com a história do Mario e do armário hein...