Goto xxx

Goto em C é utilizado com dois propósitos, o primeiro é para centralizar a limpeza de recurso em uma função, o segundo é para opter performance em interpretadores baseados em opcodes, que permite utilizar direct-threading (não tem relação com threads do Java). No primeiro caso a alternativa é mais feia que não usar goto, então é um sacrificio medido.

trolling???
O que eu disse de mais?

Louds,

Exato e o seguinte, hoje criticamos GOTO pois implementar Orientado a Objetos é muito comum agora quero ver criar sistemas grandes com linguagens estruturadas a 10, 12 anos atrás sem utilizar GOTO. Desenvolvi durante muito tempo em C e a gente evitava ao máximo utilizar GOTO, mas as vezes a própria limitação da linguagem estruturada nos obrigava a utilizar.

Abraços.

[quote=rogeriop80]
Exato e o seguinte, hoje criticamos GOTO pois implementar Orientado a Objetos é muito comum agora quero ver criar sistemas grandes com linguagens estruturadas a 10, 12 anos atrás sem utilizar GOTO. Desenvolvi durante muito tempo em C e a gente evitava ao máximo utilizar GOTO, mas as vezes a própria limitação da linguagem estruturada nos obrigava a utilizar.

Abraços.[/quote]

Interessante. Se importa de comentar um exemplo onde uma linguagem procedural não resolveria um problema sem GOTO?

Até onde eu sei, nenhuma linguagem estruturada tem suporte a exceptions. Dado o seguinte código:


int check_abc (char * file) {
   FILE *f = NULL;
   f = fopen (file, "r");

   if (!f) return -1;

   if (fgetc (f) != 'a') {
      fclose (f);
      return -2;
   }

   if (fgetc (f) != 'b') {
      fclose (f);
      return -2;
   }

   //... mais 1 monte de testes feito o if anterior

   fclose (f);
   return 0;
}

Fica muito mais facil de manter se for escrito assim:

int check_abc (char * file) {
#define FAILED goto __failed;
   FILE *f = NULL;
   f = fopen (file, "r");

   if (!f) return -1;

   if (fgetc (f) != 'a')
      FAILED;

   if (fgetc (f) != 'b')
      FAILED;

   //... mais 1 monte de testes feito o if anterior

   fclose (f);
   return 0;

__failed:
   fclose (f);
   return -2;
#undef FAILED
}

Não é uma questão de não ser possivel escrever sem GOTO, mas de ficar mais facil, o código de limpeza, nesse caso “fclose(f)”, fica restrito a um lugar apenas. Se estivesse usando Java, seria um try/finally.

Nesse caso o problema não é do paradigma, é da linguagem. Ser OO não implica ter exceções também.

O exemplo do Louds foi perfeito!!!

Até onde eu sei, nenhuma linguagem estruturada tem suporte a exceptions. Dado o seguinte código:


int check_abc (char * file) {
   FILE *f = NULL;
   f = fopen (file, "r");

   if (!f) return -1;

   if (fgetc (f) != 'a') {
      fclose (f);
      return -2;
   }

   if (fgetc (f) != 'b') {
      fclose (f);
      return -2;
   }

   //... mais 1 monte de testes feito o if anterior

   fclose (f);
   return 0;
}

Fica muito mais facil de manter se for escrito assim:

int check_abc (char * file) {
#define FAILED goto __failed;
   FILE *f = NULL;
   f = fopen (file, "r");

   if (!f) return -1;

   if (fgetc (f) != 'a')
      FAILED;

   if (fgetc (f) != 'b')
      FAILED;

   //... mais 1 monte de testes feito o if anterior

   fclose (f);
   return 0;

__failed:
   fclose (f);
   return -2;
#undef FAILED
}

Não é uma questão de não ser possivel escrever sem GOTO, mas de ficar mais facil, o código de limpeza, nesse caso “fclose(f)”, fica restrito a um lugar apenas. Se estivesse usando Java, seria um try/finally.

[/quote]

Goto já não é considerado boa prática há uns quarenta anos. E nem vem dizer que é inevitável usar GOTO em C. Olha seu código, não está seguindo a programação estruturada! Tudo bem, a questão do exception é complicada, mas seria possível escrever esse código sem utilização de goto, fazendo assim:

int check_abc (char * file) {
#define FAILED { fclose(f); return -2; }
   FILE *f = NULL;
   f = fopen (file, "r");

   if (!f) return -1;

   if (fgetc (f) != 'a')
      FAILED

   if (fgetc (f) != 'b')
      FAILED

   //... mais 1 monte de testes feito o if anterior

   fclose (f);
   return 0;

#undef FAILED
}

E um melhor, sem define e seguindo mais ainda a programação estruturada.

int check_abc (char * file) {
   int retValue = 0;
   FILE *f = NULL;
   f = fopen (file, "r");

   if (f) {
      if (fgetc (f) == 'a') {
         if (fgetc (f) == 'b') {
         //... mais 1 monte de testes feito o if anterior
            // faça o que quiser com o arquivo
         } else
            retValue = -2;
      } else
         retValue = -2;
      // tenho que fechar o arquivo de qualquer jeito
      fclose(f);
   } else
      retValue = -1;
   
   return retValue;
}

É claro que isso pode entrar em gosto pessoal, mas se fosse fazer em C, eu fazia (e realmente eu fazia, antes de entrar no Java) como esse último código mostrado.

Leonardo3001,

Você fez duas versões do código original sem utilização de goto. Mas vc se esqueceu que sua versão faz exatamente a mesma coisa que o goto, ou seja, fica igual.
O problema todo não é a sintaxe “goto label;” Mas sim a semântica “vá em algum lugar do código e faça alguma coisa”. A questão nativa é a legibilidade, e no seu caso, ficou EXATAMENTE igual a versão utilizando goto!!!
Isso acontece porque geralmente ensinam programação e dizem que é terrível a utilização do goto. O cara aprende a não usar e odiar o goto mas faz uma “gambiarra” que causa a mesta desestruturação que o goto…
Isso ai, é trocar 1GB por 1024MB…

Ele substituiu goto por uma macro mais complexa. E isso também é um tanto questionável. As macros desaparecem antes mesmo da compilação, e são difíceis de se depurar. Além de ter a chance de gerar um comportamento inesperado. É fato que ele restringiu a macro apenas a função dele, o que melhora muito as coisas. Acho que aqui é uma questão de gosto pessoal, eu ainda prefiro a solução do Louds, mesmo com os gotos. Que aliás, é parcialmente adotada pelo Visual Basic, como mecanismo oficial da linguagem.

Mas… veja bem. A pergunta a oficial do tópico é: Porque o Java não suporta goto? Se remontarmos a origem histórica do goto, claro, acharemos os locais onde, para época, ele era uma boa solução. É capaz até de, se pegarmos livros daquela época, acharmos recomendações envolvendo goto.

O fato é que isso causou uma boa dose de dor de cabeça para os programadores da época. E programadores aprendem com os erros e melhoram os seus programas. Criam paradigmas melhores e técnicas melhores. E graças a isso, o comando se tornou obsoleto hoje em dia.

Se você usar Java, ou mesmo C++, você realmente deve odiar o goto (exceto talvez nas situações que descrevi ali em cima). Nessas linguagens já há maneiras muito superiores de se resolver o problema. Assim como deve odiar retornar "códigos de erro" no lugar de exceptions, ou ainda desconfiar muito quando estiver escrevendo switchs.

PS:

[code]
int x = 2;
int y = 1;
//Como exemplo de macro que gera comportamento inesperado, conside a clássica:
#define MAX((a),(b)) (a) > (b) ? (a) : (b)

//Veja o que acontece se fizermos:
int z = MAX(x++, y); //Notem que parece uma função, mas é macro.

//Esse código é substituido por:
int z = x++ > y ? x++ : y;

//Quantas pessoas notariam que x é somado 2 vezes?[/code]

É possivel fazer um tipo de ‘tratamento de excessões’ em C sem goto, via setjump/longjump :wink:

Olá! GOTO foi banido pq com o advento da orientação a objetos fica confuso utilizá-lo, já para um para linguagens de programação estruturada como o puro asm NÃO há como fazer uma aplicação sem o uso do JUMP (JSR, LJMP, etc.). Agora citar que o GOTO é coisa de usuário dummy acho que é um pouco “sem noção”… qm duvida, que vá implementar um protocolo de comunicação qlqr em asm, por exemplo.

E quase um ano depois… alguém desenterra o tópico! :o

Só um comentário. No caso específico de protocolos de comunicação de tempo real (telefonia, por exemplo), muitos são implementados em hardware. E, portanto, em assembly e C.

E, nesses casos, usa-se goto.

import com.sun.org.apache.bcel.internal.generic.GOTO;

int i=0;
a:
System.out.println(1123123);
i++;

    if(i==0)
    {
    	GOTO a;
    }

funciona que uma beleza!!

Então como eu faria no meu problema abaixo sem apelar pro “temível” GOTO?

[code]// ESCOLHA
opcao = Integer.parseInt(JOptionPane.showInputDialog(null,“Digite um número entre 1 e 4:”));

switch(opcao) {
case 1:

break;
case 2:

break;
case 3:

break;
case 4:

break;
default:
JOptionPane.showInputDialog(null,“Opção inválida! É entre 1 e 4 seu animal. =P”);
// volte para a ESCOLHA
}[/code]
No caso eu não quero colocar um IF ELSE por fora pq não quero o encerramento do programa, quero que o usuário corrija sua escolha na mesma execução.

Flws!

E a propósito, você não vai subir na vida se tratar o usuário como “animal”. É ele que paga seu salário :stuck_out_tongue:

// ESCOLHA
do {
    opcao = Integer.parseInt(JOptionPane.showInputDialog(null,"Digite um número entre 1 e 4:"));
    switch(opcao) {
       case 1:
          ...
          break;
       case 2:
          ...
          break;
       case 3:
          ...
          break;
       case 4:
          ...
          break;
       default:
          JOptionPane.showInputDialog(null,"Opção inválida! É entre 1 e 4 seu animal. =P");
          // volte para a ESCOLHA
    }
} while (opcao < 1 || opcao > 4);

Se convencer esse pessoal que goto é uma péssima prática, imagina dizer que null references foi um erro de um bilhão de dólares.

No próprio Basic, o goto já podia ser substituido por gosub, criando o nível 1 de encapsulamento, as sub-rotinas. E no Basic que programei (TK2000 II-Color) o goto era feito para uma linha de código e não para um “label” o que degradava mais ainda a legibilidade do código.

Não lembro de goto no Clipper e nem no Object Pascal.

Vlws ae!

E de boa, akele “esporro” seria só pra deixar esse exemplo cômico! ^^

Engraçado q eu tinha pensado no DO WHILE, mas estava colocando-o no lugar errado. :-\

E no caso eu nunca iria conseguir usar o BREAK do Java, pois ele teria q ser assim:

loop: ... ... ... break loop;
Teria que ir para cima do código e não pular pra uma parte abaixo dele…

Flws!

Olha, eu realmente não gosto de usar o goto, mas algumas vezes por questão de performance, temos que acabar usando…

É que nem mixturar com assembly, torna teu codigo dependente de plataforma, mas em algum casos é a melhor opção se não a unica.

Pra pucrs, eu tavah fazendo um exercicio de optimização de algoritimos…

era pra gerar um milhão de numeros primos, eu consegui em 3 segundos, e para isso eu usei varios laços de repetição, um deles dentro do verificador do numero, para ver se é composto ou primo. Este laço tinha que executar uma vez testando no maximo ate onze, matando a maior parte dos numeros, e se terminase sua execução teria que testar ate a raiz para ter certeza que o numero era primo…

Por questões obvias de performance, clareza (não repetir a mesma coisa), e uso de memoria, optei pelo goto para retornar ao mesmo laço, mas com outros parametros…

O problema é que tenho que entregar em Java, e o mesmo algoritimo em java, leva por volta de 45 segundos para executar sem este tweak…

O codigo segue abaixo:

/*
 *  Primos.c
 *  
 *
 *  Created by Marcos Sartori on 28/10/2009.
 *  Copyright 2009 Marcos Sartori Computer Systems. All rights reserved.
 *
 */

#include <stdio.h>
#include <math.h>

#define TRUE -1
#define FALSE 0

int main (int argc, char* argv)
{
	unsigned register int i, z;
	i = 0; z = 0;
	
	while (z<=1000000){
		if (isPrime(i)){
			printf("%d\n", i);
			z++;
		}
		i++;
	}
	//printf("0x%08X\n", i);
	
	return 0;
}

int isPrime(unsigned int aNumber)
{
	unsigned register int i, z, j;
	
	if (aNumber<=1) return FALSE;
	if ((!(aNumber&1))&&(aNumber!=2)) return FALSE;
	
	z=aNumber<=11?aNumber-1:11; goto loop;
	
sqrt:
	z=sqrt(aNumber); j = TRUE;
loop:
	for (i=3; i<=z; i+=2)
		if (!(aNumber%i)) return FALSE;
	if(!j) goto sqrt;
	
	return TRUE;
}

Se tiver algum Japhilopho que saiba como conseguir um suquinho de performance do java, me retornem por favor…