Desafio da Semana #3



 


DESAFIO DA SEMANA #3


 


 


Por: Roberto Alexis Farah


 


Oi pessoal!


Dessa vez o desafio ilustra uma situação que pode ocorrer quando projetos são migrados de VB.NET para C# ou vice-versa.


 


CENÁRIO


 


Um cliente por uma razão qualquer decidiu parar o desenvolvimento de uma aplicação em C# e usar VB.NET. Entretanto, após converter a aplicação de C# para VB.NET ele notou que, embora simples, o comportamento da aplicação era diferente nas duas linguagens de programação.


Ele checou o código fonte e concluiu que a lógica era a mesma, portanto, ele pede seu auxílio para identificar o PROBLEMA e propor uma SOLUÇÃO.


Para você poder reproduzir o problema ele criou uma aplicação muito simples que reproduz o mesmo sintoma encontrado na aplicação.


 


SINTOMAS


 


Aplicação C# retorna       100 e -60 como resultado. Esse é o resultado esperado.


Aplicação VB.NET retorna 150 e -5   como resultado. Esse resultado é incorreto.


 


 


PROBLEMA


 


Identifique e explique porque há essa diferença de comportamento.


 


SOLUÇÃO


 


Proponha uma solução simples que resolva o problema.


 


 


INSTRUÇÕES


 


Crie uma aplicação C# console com o seguinte código:


 


using System;


using System.Collections.Generic;


using System.Text;


 


namespace CSharp


{


           


    class Program


    {


                        static int sum = 50;


                        static int subtraction = 100;


                           


        static void Main(string[] args)


        {         


           if((DoSubtraction() > 0) || (DoSum() > 0))


           {


                                       Console.WriteLine(“Valor da soma das variaveis = {0:d}\n”, sum + subtraction);             


           }


         


         sum = -5;


           


          if((DoSubtraction() < 0) && (DoSum() < 0))


          {


                                      Console.WriteLine(“Valor da soma das variaveis = {0:d}\n”, sum + subtraction);             


          } 


          else


         {


                                     Console.WriteLine(“Valor da subtracao das variaveis = {0:d}\n”, sum – subtraction);                      


         } 


            


       } // Main


 


       static int DoSubtraction()


       {


            return subtraction -= sum;


       }


 


       static int DoSum()


       {


            return sum += subtraction;


       }


              


    } // namespace.


 


}


 


 


E crie uma aplicação VB.NET console com o seguinte código:


 


Module Module1


            Dim sum As Integer = 50


            Dim subtraction As Integer = 100


 


    Sub Main()


                        If (DoSubtraction() > 0) Or (DoSum() > 0) Then


                                       Console.WriteLine(“Valor da soma das variaveis = {0:d}”, sum + subtraction)


                        End If


 


                        sum = -5


 


                        If (DoSubtraction() < 0) And (DoSum() < 0) Then


                          Console.WriteLine(“Valor da soma das variaveis = {0:d}”, sum + subtraction)


                        Else


                         Console.WriteLine(“Valor da subtracao das variaveis = {0:d}”, sum – subtraction)


                        End If


 


    End Sub


            Function DoSubtraction() As Integer


                        subtraction -= sum


                        DoSubtraction = subtraction


                        Exit Function


            End Function


 


            Function DoSum() As Integer


                        sum += subtraction


                        DoSum = sum


                        Exit Function


            End Function


End Module


 


Agora é possível reproduzir os sintomas e depurar.


 


Boa sorte!


 


 

Comments (3)

  1. Danilo Pimentel says:

    Olá amigos,

    Após analisar o resultado gerado pela execução dos aplicativos nas duas linguagens podemos constatar a diferença… Os valores retornados realmente são muito diferentes.

    Analisando superficialmente os códigos acreditamos que a lógica na "tradução" de uma linguagem para outra está correta. No entanto, se formos mais criteriosos, observaremos que há um erro clássico ocorrendo aí…

    O erro está apenas na diferença para as condições definidas por:

    =========================================

    C#

    =========================================

    if((DoSubtraction() > 0) || (DoSum() > 0))

    e

    if((DoSubtraction() < 0) && (DoSum() < 0))

    =========================================

    VB

    =========================================

    If (DoSubtraction() > 0) Or (DoSum() > 0) Then

    e

    If (DoSubtraction() < 0) And (DoSum() < 0) Then

    ***********************************

    C#

    É de nosso conhecimento que, logicamente, a operação OR é avaliada como sendo verdade quando qualquer um dos termos é verdadeiro (Sendo assim não é necessário testar o segundo termo caso o primeiro seja verdadeiro).

    Também é de nosso conhecimento que, logicamente, a operação AND é avaliada como sendo verdade quando os dois termos são verdadeiro (Sendo assim não é necessário testar o segundo termo caso o primeiro seja falso, pois isso já invalida a operação).

    No exemplo em C# podemos notar esses dois simples conceitos aplicados de forma extremamente eficiente:

    Na primeira condição, após avaliar o resultado de DoSubtraction(), a condição já tem sua avaliação lógica montada e definida como TRUE, pois o primeiro termo é TRUE e a operação lógica que está sendo realizada é um OR, então o segundo termo DoSum() não é avaliado e, portanto, a função não é executada.

    Na segunda condição, após avaliar o resultado de DoSubtraction(), a condição já tem sua avaliação lógica montada e definida como FALSE, pois o primeiro termo é FALSE e a operação lógica que está sendo realizada é um AND, então o segundo termo DoSum() não é avaliado e, portanto, a função não é executada.

    ***********************************

    VB

    Na execução do Visual Basic, para se realizar o teste da condição, seja ela "OR" ou "AND", todos os termos são testados para encontrar-se a condição lógica final. Portanto as funções DoSubtraction() e DoSum() são executadas em ambas condições.

    Devido a forma como o programa está implementado, a execução de cada uma dessa funções interfere no resultado final visto que ambas alteram o valor de variáveis globais que são utilizadas para o resultado final.

    +++++++++++++++++++++++++++++++++++

    SOLUÇÃO

    Para que o resultado do programa em Visual Basic seja o mesmo que o resultado em C# é necessário fazer uma adequação no código. Precisamos testar de forma separada cada um dos termos, condicionando a necessidade de se avaliar o segundo termo nas condições.

    Uma adequação possível pode ser expressa por:

    ‘=======================

           Dim bOk As Boolean

           bOk = (DoSubtraction() > 0)                ‘Avalia o primeiro termo

           If Not bOk Then bOk = (DoSum() > 0)        ‘Se o for FALSE, precisamos avaliar o segundo…

           If (bOk) Then

               Console.WriteLine("Valor da soma das variaveis = {0:d}", sum + subtraction)

           End If

           sum = -5

           bOk = (DoSubtraction() < 0)                ‘Avalia o segundo termo

           If bOk Then bOk = (DoSum() < 0)            ‘Se for TRUE, precisamos avaliar o segundo…

           If (bOk) Then

               Console.WriteLine("Valor da soma das variaveis = {0:d}", sum + subtraction)

           Else

               Console.WriteLine("Valor da subtracao das variaveis = {0:d}", sum – subtraction)

           End If

    ‘=======================

    É isso aí pessoal, até a próxima.

    Abraços,

    Danilo Pimentel

  2. Roberto A. Farah says:

    Olá Danilo!

    Obrigado pela sua participação constante nos desafios!

    Novamente você mandou muito bem! 🙂

    Sua explicação sobre o problema está correta e a solução proposta também. Entretanto, há um modo de resolver o problema com uma solução que não envolve mudar a lógica do if explicitamente, e sim, usando comandos do próprio Visual Basic .NET, tornando a solução mais simples e menos trabalhosa.

    Estou publicando a resposta agora.

  3. Danilo Pimentel says:

    Nossa Roberto! Que legal! Realmente não sabia da existência desses outros operadores que forçavam a mudança do fluxo de execução.

    Muito obrigado, acho que essa informação é útil para todos nós.

    Parabéns pelo blog!