Quais estruturas de controle alternativas úteis você conhece? [fechadas]

12

Pergunta semelhante foi encerrada no SO.

Às vezes, quando estamos programando, descobrimos que alguma estrutura de controle específica seria muito útil para nós, mas não está diretamente disponível em nossa linguagem de programação.

Quais estruturas de controle alternativas você acha que são uma maneira útil de organizar a computação?

O objetivo aqui é obter novas formas de pensar sobre a estruturação do código, a fim de melhorar o chunking e o raciocínio.

Você pode criar uma sintaxe / semântica desejada agora não disponível ou citar uma estrutura de controle menos conhecida em uma linguagem de programação existente.

As respostas devem fornecer idéias para uma nova linguagem de programação ou aprimorar uma linguagem real.

Pense nisso como um debate de ideias, então publique algo que você acha que é uma ideia maluca, mas que pode ser viável em alguns cenários.

É sobre programação imperativa.

Maniero
fonte
1
Por que essa pergunta tem que ser sobre "programação imperativa"?
missingfaktor
@missingfaktor: Porque estruturas de controle são sobre programação imperativa. Certamente, alguns problemas podem ser resolvidos com abordagem funcional ou de outra maneira, mas outros paradigmas não colocam estruturas de controle no centro do desenvolvimento. Mas de qualquer maneira você pode ser criativo.
Maniero
3
Bem, eu ia compartilhar a correspondência de padrões com os guardas, já que essas são mais gerais que as declarações Case e If-Thens, mas se essa é uma zona sem FP, acho que é apenas mais correspondência de padrões para o resto de nós!
CodexArcanum 29/11
@ CodexArcanum: Bem, a correspondência de padrões é uma construção muito semelhante às construções imperativas. De fato, a correspondência de padrões em si é uma alternativa às estruturas de controle imperativas. Não seja tímido ;-)
Maniero
Observar todas as respostas me deixa feliz por nenhuma das propostas existir na vida real (e espero que nunca existirá). Desculpe :)
serg

Respostas:

14

OK, esta é uma pergunta divertida.

Eu também gostaria de ter um general elsepor enquanto e por loops, para quando a condição não for verdadeira no primeiro teste:

while (condition) {
    // process
}
else {
    // condition was never true
}

Isso evita o recálculo incômodo da condição ou o armazenamento em uma variável.

Macneil
fonte
Python tem isso.
Barry Brown
Ei! Finalmente, uma escolha peculiar de Python com a qual concordo! ;-)
Macneil 28/11
5
Não. A cláusula else no Python para loops for / while é executada se o loop terminar normal, o que significa que o loop não será encerrado por meio de uma instrução de quebra ou retorno ou de uma exceção. Nos loops for, o clasuse else é executado depois que a sequência de elementos que é colocada em loop é esgotada e, enquanto os loops são executados após a condição do loop ser avaliada como False pela primeira vez.
pillmuncher
4
uma solicitação para adicionar a while ... elseconstrução da maneira que Macneil a descreve no PHP. Eu acho que é uma ótima idéia, porque o "aqui estão os resultados / não houve resultados" é um idioma bastante comum nos aplicativos da web.
Dean Harding
1
@ SnOrfus: Ele quer um bloco de código (separado do bloco do loop) que executa SOMENTE se a condição while nunca for atendida. Do-While executa o bloco de código do loop (não algum bloco separado) uma vez, independentemente do tempo condicional.
Legion
10

Por que não misturar algumas respostas em uma?

while (expr) {

    // Executed every iteration, unless first{} is present.
    // May be explicitly called rest{} if you like first{} to come first.

    // Blocks may return results, and consequently be used in expressions.
    return expr;

} first {

    // Executed only on the first iteration.

} pre {

    // Executed before every iteration.

} post {

    // Executed after every iteration.

} catch (oops) {

    // All blocks are implicitly try{}ed if followed by a catch{}.

} finally {

    // Executes after the block completes, regardless of exceptions.

} else {

    // Executed if the loop body or rest{} never executes.

} never {

    // Executes only when a client is present.

} drop (bad, worse), // Explicitly ignore certain exceptions.
  until (expr);      // Here, have a post-body condition, too.

Uma sintaxe de construção de controle de fluxo generalizada e extensível em uma linguagem imperativa seria bastante útil e divertida. Até que isso apareça, acho que vou usar o Lisp ou algo assim.

Jon Purdy
fonte
5
Não é útil, confuso. Não é divertido, lento.
Josh K
2
@ Josh K: Sim, você está certo. Você pensou que eu discordaria? Essa resposta está mordendo a língua para não rir.
Jon Purdy 29/11
Se era para ser irônico, certamente conseguiu!
Josh K
11
+1 me fez rir. Precisa de uma cláusula "between", para que o código seja executado entre iterações.
Barry Brown
1
+1, mas também precisa de um seventh { ... }.
Jrandom_hacker
7

Estruturas de controle como funções.

Quero for, if, else, while, etc, para ser funções, e não estruturas especiais.

Eu quero return, try/excepte gotoser derivado de continuações.

É claro que isso tem menos a ver com uma estrutura de controle específica e mais com a forma como você vê as estruturas de controle em geral, a meta das estruturas de controle.

dietbuddha
fonte
2
Continuações são um conceito pesado para um idioma e há boas razões para deixá-los fora de vários idiomas.
David Thornley 29/11
Eu não discordo; tendo for, if, else, e whilecomo as funções que me faz inferir que os parâmetros para essas funções precisam ser preguiçosamente executado, a fim de comportar o mesmo que as construções originais. Ter a capacidade de executar preguiçosamente seria bom.
Aprendiz do Dr. Wily
1
@ David: Só porque eles estão lá, não significa que você tem que usá-los. Programadores regulares podem usar o que estão acostumados return, exceções, etc. Mas agora o programador especialista possui uma ferramenta adicional poderosa em sua caixa de ferramentas, se necessário. Além disso, as línguas IMHO não devem ser "emburrecidas". Os idiomas devem ter a capacidade de oferecer suporte ao aumento da experiência e ao crescimento do conhecimento em CS.
dietbuddha
1
@dietbuddha: (cont) Eu não estou dizendo que continuações são ruins, estou dizendo que são pesadas, e torná-las utilizáveis ​​tem implicações para a linguagem, algo como exceções. Além disso, ter continuações provavelmente forçará mudanças na maneira como as pessoas usam a linguagem, novamente como exceções em C ++. Uma linguagem que suporta continuações será diferente de uma que não suporta, tanto de maneiras boas quanto ruins.
precisa
1
@ Steve314 - longjmp não é uma continuação, embora haja semelhanças. As continuações salvam todo o estado (todos os habitantes locais, globais e a pilha). O longjmp salva um ponteiro de pilha; portanto, se você ultrapassar o escopo em que o setjmp foi usado, receberá um segfault, pois o quadro não existe mais. Eu acredito que também existem algumas limitações nas variáveis ​​que ele salva.
dietbuddha
6

O artigo vinculado definitivamente esclarece os N + 1/2 Loops de Donald Knuth . Expressado em C / C ++ / Java:

for (;;) {
  get next element;
  if (at the end) break;
  process the element;
}

Isso é útil para ler linhas ou caracteres de um arquivo, testar se você atingiu o EOF e depois processá-lo. Estou tão acostumado a ver o padrão for(;;)..if(..)break;aparecer que é idiomático para mim. (Antes de ler o artigo de Knuth, reimpresso no livro Literate Programming , este costumava ser um "wtf?".)

Knuth sugeriu as palavras loop/while/repeat- chave :

loop:
  S;
while C:
  T;
repeat

Onde Se Tsão espaços reservados para uma série de zero ou mais instruções e Cé uma condição booleana. Se não houvesse uma Sinstrução, seria um loop while e, se não houvesse uma Tinstrução, seria um loop do.

Essa construção em si poderia ser generalizada, permitindo zero ou mais while Ccláusulas, tornando-a perfeita para expressar loops infinitos e, em seguida, algumas condições mais raras que precisariam de duas verificações.

No mesmo artigo, Knuth sugeriu um mecanismo de sinalização que seria uma versão local de exceções de lançamento / captura (como uma alternativa ao uso de goto).

Para mim? Desejo que a Java suporte a otimização de chamada de cauda, ​​para que eu possa expressar qualquer estrutura de controle geral, conforme necessário.


Atualização: esqueci de mencionar que muitos programadores de C / C ++ / Java resolvem esse problema usando uma atribuição incorporada na condição de while:

while ((c = getc(f)) != -1) {
   T;
}

Usando os termos da construção de Knuth, isso é permitido quando Se Cpode ser combinado em uma única expressão. Algumas pessoas odeiam ver a atribuição incorporado acima, enquanto outros odeiam ver o breakno for (;;)acima. Mas quando Se Cnão pode ser combinado, como quando Spossui várias instruções, for (;;)é a única alternativa sem repetir o código. A outra alternativa é simplesmente duplicar o Scódigo:

S;
while (C) {
  T;
  S;
}

A loop/while/repeatalternativa de Knuth parece muito melhor.

Macneil
fonte
Esse loop enquanto repete se parece muito com o repeat-untilloop Pascal .
Mason Wheeler
@Mason: A diferença é que existem dois lugares onde você pode inserir instruções mais sua condição, e não apenas uma.
Macneil
Oh, eu vejo o que está acontecendo. Sim, isso é interessante ...
Mason Wheeler
O ANSI Basic tinha do while ... loop until- a pré-condição e a pós-condição são opcionais, e eu (vagamente) lembro de usar as duas em um loop. Para sua condição intermediária, há o Ada exit when ...;. A principal vantagem if ... break;é que você pode escrever exit loopname when ...;para sair de vários loops aninhados (mas não necessariamente todos) ao mesmo tempo. Provavelmente um pouco mais visível do que essa pausa também.
Steve314
Coisa engraçada. Ada tem exatamente esse recurso.
John R. Strohm
6

A linguagem BCPL tinha uma valueofexpressão que poderia ser usada para transformar uma sequência de instruções em uma única expressão:

foo(a, b, valueof {some series of statements; resultis v});

Onde some series of statementspode haver qualquer coisa e o todo é valueofavaliado v.

Isso pode ser útil em Java para quando você precisar calcular um argumento para chamar um this()ou super()(que requer que nada aconteça antes dele). Obviamente, você pode simplesmente escrever um método separado, mas isso pode ser um problema se você precisar passar muitos valores locais para o contexto.

Se você puder usar as finalvariáveis ​​necessárias, já poderá fazer um valueofem Java usando classes internas anônimas:

foo(a, b, new Object(){String valueof(){
    String v ...; some series of statements; return v;}}.valueof());
Macneil
fonte
1
O GCC tem uma extensão para isso - ({ statement1; statement2; ...; result-expr; }). Vi outros lugares semelhantes também, mas não me lembro onde. Provavelmente todos copiados do BCPL, no entanto.
Steve314
6
unless(condition) {
  // ...
}

faz o mesmo que:

if(!condition) {
  // ...
}

repeat {
  // ...
} until(condition)

faz o mesmo que:

do {
  // ...
} while(!condition)
desaparecido
fonte
Você pode querer ir para Lisp ...
duros 28/11
1
Ou Ruby, tem sintaxe semelhante para unless.
Josh K
2
Parece bastante perlish. Há mais de uma maneira de fazer isso.
2
@ Steve314 Você deve usar um estilo de chave incorreto . ;-)
Orbling
1
@ Orbling - de jeito nenhum. Todos os outros usam um estilo de chave incorreto.
Steve314
5

Em uma nota diferente, eu gostaria de ver um melhor suporte para iteradores nas linguagens de programação. Em particular, para quando você quiser descer duas coleções em pares :

for (String s, Integer i : stringsSet, integersSet) {
    // use the pair (s, i)
}

Algumas linguagens dinâmicas já podem ter isso, ou suportam facilmente via bibliotecas e macros, mas acho que isso está no espírito da sua pergunta.

Se os dois conjuntos não tiverem o mesmo tamanho, isso poderá gerar uma exceção ou um elseloop após o sinalizar que houve uma diferença nos tamanhos.

Naturalmente, você pode generalizar isso ao descer três ou mais listas.


Atualização: Também seria útil fazer o produto cartesiano entre iteráveis:

for (String s, Integer i : stringsSet * integersSet) {
    // use the pair (s, i), each s with each i
}

que seria nada mais que loops aninhados:

for (String s : stringsSet) {
    for (Integer i : integersSet) {
        // use the pair (s, i), each s with each i
    }
}

Estou um pouco preocupado que, entre as duas notações que forneço aqui, exista uma diferença de O (n) e O (n ^ 2) no número de pares, apenas com a alteração de um único caractere.

Macneil
fonte
2
No Python, há zip e zip_longest que fazem isso.
pillmuncher 29/11/10
Legal, talvez eu esteja subestimando o Python e deva dar uma segunda olhada depois de muitos anos. Isso me lembra que, às vezes, você também deseja o produto cartesiano, o equivalente a aninhado para loops.
Macneil 29/11
1
Ambos os casos em Scala: paste.pocoo.org/show/297429
missingfaktor
1
Em referência ao produto cartesiano: Novamente, o Python possui. for a, b, c in itertools.product(iter1, iter2, iter3):dá-lhe o produto cartesiano avaliado preguiçosamente. O que é isso? Você deseja permutações e combinações de um determinado iterador também? itertools.permutations, itertools.combinations.
aaronasterling
1
Perspectiva de Haskell: use "zipWith" para o primeiro caso e compreensão da lista ou a mônada da lista para o segundo. Como os exemplos de Python / Scala, mas mais elegantes. :)
LennyProgrammers
5

Existe o chamado "Dijkstra's Loop" (também chamado "Dijkstra's Guarded Loop"). Foi definido na The Guarded Command Language (GCL) . Você pode encontrar algumas informações sobre a sintaxe e a semântica no artigo da Wikipedia acima, na seção 6 Repetição: do .

Atualmente, conheço uma linguagem de programação que suporta diretamente essa estrutura de controle. É Oberon-07 (PDF, 70 KB). E suporta "Loop de Dijkstra" na sua forma de declaração while. Veja a seção 9.6. Declarações While no PDF acima.

WHILE m > n DO m := m – n 
ELSIF n > m DO n := n – m 
END

PS Esta é uma cópia da minha resposta SO .

Gato selvagem
fonte
Parece que o verificador de modelo Spin também possui essa construção, com semântica idêntica e sintaxe basicamente idêntica.
Jrandom_hacker
4

Expressões em estilo de ícone com retorno interno.

O Python obtém muitos dos benefícios do gerador de ícones - e faz um trabalho melhor deles em geral, a IMO. E, em princípio, o retorno era apenas um tipo de exceção, mas era a simplicidade das expressões o equivalente aproximado de ...

x = (a / b) else c;

para lidar com casos de falha, como divisão por zero.

Onde Icon ficou louco - não há operadores de comparação com retorno booleano. As comparações sempre foram bem-sucedidas ou desencadearam o retorno, e havia outra questão semântica que agora estou tentando desesperadamente lembrar que ... bem, digamos que provavelmente seja mais reprimida do que esquecida.

Eu sempre pensei que eles deveriam ter uma ifexpressão sem outra parte - if (condition, success-value)tipo de coisa, voltando atrás se a condição retornar falsa - e descartar as comparações estranhas.

EDIT Lembro-me - óbvio realmente. Uma comparação com dois argumentos é bem-sucedida ou falha - ela não calcula um novo valor para retornar. Então, quando for bem-sucedido, o que ele retornará? Resposta - um dos argumentos. Mas se você escrever a > b, qual é o argumento lógico para retornar - aou b? E se você escrever b < a? Eu acho que sempre retornou o argumento certo, o que faz tanto sentido quanto qualquer outra coisa, mas ainda assim normalmente parecia o argumento errado para mim.

Steve314
fonte
4

Esta é apenas uma ideia e sintaxe gerais:

if (cond)
   //do something
else (cond)
   //do something
also (cond)
   //do something
else
   //do something
end

A condição TAMBÉM é sempre avaliada. ELSE funciona como de costume.

Também funciona para o caso. Provavelmente, é uma boa maneira de eliminar a declaração de quebra:

case (exp)
   also (const)
      //do something
   else (const)
      //do something
   also (const)
      //do something
   else
      //do something
end

pode ser lido como:

switch (exp)
   case (const)
      //do something
   case (const)
      //do something
      break
   case (const)
      //do something
   default
      //do something
end

Não sei se isso é útil ou simples de ler, mas é um exemplo.

Maniero
fonte
3

O estilo de passagem de continuação vem à mente. Então, é claro, você também gostaria de ter a Otimização de chamada de cauda .

pillmuncher
fonte
1
Não sou um grande fã disso, e não acredito que seja realmente uma "estrutura de controle", mas sim um bloco de construção em linguagens funcionais e estilo de programação. O Node.js parece bastante viciado nele.
Josh K
1
Claro que é uma estrutura de controle. Não é apenas aquele que vem com uma palavra-chave como 'if' ou 'for', mas como um padrão para estruturar o fluxo de controle (portanto, estrutura de controle). É até usado nos bastidores por muitos compiladores. E também não se limita aos FLs. Você precisa de funções como Objetos de Primeira Classe.
pillmuncher
1
Hoje em dia, você obtém otimização de chamada em C e C ++, mas na IMO ela perde o sentido. O ponto é que é uma otimização. No esquema, uma chamada de cauda genuína é óbvia. Especialmente em C ++, muitas coisas podem significar que sua chamada final não é uma chamada final. E o excesso de pilha significa que seu aplicativo está com problemas. Na IMO, deve haver algo como uma goto return ...;declaração, tornando explícita a intenção de chamar a cauda, ​​portanto, se o compilador não puder torná-lo iterativo, será um erro.
Steve314
1
@ Macneil - que eu sei com certeza, a otimização da chamada de cauda é feita no GCC, Clang e Visual C ++. O GCC possui conversões mais sofisticadas de recursão para iteração, que podem lidar com vários casos que não são recursivos finais. Mas muita coisa pode dar errado. Passe um ponteiro para uma variável local nessa chamada final e o quadro da pilha não pode ser eliminado, pois a variável precisa ser mantida ativa. No C ++, os destruidores de variáveis ​​locais normalmente acontecem após o retorno da chamada "final", o que significa que não é uma chamada final.
Steve314
1
@ Mike - esse é o meu ponto. Se você usar um estilo de codificação recursiva, sem a chamada de "otimização", seu código poderá estar quebrado, pois o estouro de pilha é um erro. No C ++, é uma otimização - para o compilador fazer otimizações para que você não precise, tudo bem, mas você não pode confiar nelas. Se você deseja liberdade para escrever em estilo recursivo, mas não precisa se preocupar com problemas de profundidade da pilha, a eliminação de chamadas não é otimização - é uma questão de correção. Se a recursão é a melhor maneira de codificar algo, você deve conseguir fazer isso - não precisa se preocupar com o estouro de pilha.
Steve314
3

Ramificação de encadeamento sem costura, possui sintaxe como uma função, mas é executada em um encadeamento separado e não pode acessar dados que não foram passados ​​inicialmente para ele.

branch foo(data, to, be, processed){
    //code
    return [resulting, data]
}

Quando um ramo é chamado, ele retornará imediatamente um identificador.

handle=foo(here, is, some, data)

O identificador pode ser usado para verificar se a tarefa está concluída.

handle.finished() //True if the execution is complete

Se o resultado for solicitado antes que a execução seja concluída, o encadeamento principal simplesmente aguardará.

[result, storage]=handle.result()

Isso não cobriria os cenários de multithreading mais avançados, mas forneceria uma maneira facilmente acessível de começar a utilizar vários núcleos.

aaaaaaaaaaaa
fonte
Dê uma olhada no Cilk, é uma extensão muito limpa e simples do C: en.wikipedia.org/wiki/Cilk . Não sei se ele tem um handle.finished()teste, mas spawne synctudo o que você precisa para 90% das tarefas de programação paralela.
Jrandom_hacker
3
if (cond)
   //do something
else (cond)
   //do something
else (cond)
   //do something
first
   //do something
then
   //do something
else (cond)
   //do something
else
   //do something
end

O PRIMEIRO e o THEN são executados se qualquer um dos três condicionais for avaliado como verdadeiro. O PRIMEIRO bloco é executado antes do bloco condicional e, em seguida, depois do bloco condicional.

A gravação condicional ou final ELSE após a instrução FIRST e THEN é independente desses blocos.

Pode ler-se como:

if (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   //do something
else
   //do something
end


function first()
   //do something
return
function then()
   //do something
return

Essas funções são apenas um formulário para ler. Eles não criariam escopo. É mais como um gosub / return do Basic.

Utilidade e legibilidade como assunto de discussão.

Maniero
fonte
2

Às vezes me pego escrevendo um loop que precisa fazer algo diferente durante a primeira iteração. Por exemplo, exibindo tags <th> em vez de <td>.

Eu lido com essa situação com uma bandeira booleana. Algo assim:

first = true

while (some_condition)
    if (first)
        do_something
        first = false
    else
        do_something_else

Parece bobagem verificar o valor de firsttodas as iterações quando elas serão falsas na maioria das vezes.

Eu gostaria de ter uma opção de loop para especificar um corpo de loop diferente na primeira iteração. Não haveria necessidade de uma variável separada. O código compilado também não precisaria de um, porque o código gerado teria dois corpos, um para a primeira iteração e outro para o restante.

Barry Brown
fonte
A questão SO tem uma idéia semelhante, mas com um operador "then" para ser usado em valores. Dessa forma, você provavelmente não possui código duplicado. Exemploprint(out, first "<th>" then "<td>")
Macneil 28/11
1
A melhor maneira é iniciar a iteração +1.
Josh K
1
O caso comum está em loop com manipulação entre, por exemplo, listando itens com um separador de vírgula. Estritamente, é isso if (!first) gimme-a-comma ();, mas praticamente a mesma coisa. Uma objeção que eu teria, no entanto - se você o encerrar adequadamente, acabará com coisas como o método de junção de strings Python - por mais que precise do padrão básico, o loop subjacente não precisará ser reescrito com tanta frequência.
Steve314
Como Josh diz, é claro, tirar o primeiro item do circuito é válido. No caso do separador de vírgulas, significa código duplicado, mas isso pode ser uma chamada de função duplicada. Pessoalmente, prefiro a ineficiência do if (!first), mas os micro-otimizadores podem levantar objeções de previsão de ramificação.
Steve314
1
@ Barry Brown: Desenrolar a primeira iteração do loop pode ou não ser mais rápido do que verificar um sinalizador booleano. Um preditor de ramificação decente irá predizer erroneamente as 2 primeiras iterações, eu prevejo :) Eu preferiria usar if (!first)e deixar um compilador otimizador decidir se o corpo do loop é pequeno o suficiente para que se desenrolar e se livrar firstseja uma vitória líquida.
Jrandom_hacker
1

[copiado da minha própria resposta no stackoverflow]


ignoring - Ignorar exceções que ocorrem em um determinado bloco de código.

try {
  foo()
} catch {
  case ex: SomeException => /* ignore */
  case ex: SomeOtherException => /* ignore */
}

Com uma construção de controle de ignorância, você pode escrevê-la de forma mais concisa e mais fácil como:

ignoring(classOf[SomeException], classOf[SomeOtherException]) {
  foo()
}

[Scala fornece isso (e muitas outras construções de controle de manipulação de exceção) em sua biblioteca padrão, no pacote util.control. ]

desaparecido
fonte
4
Exceções não devem ser ignoradas.
Josh K
1
Exceto que, no contexto, uma exceção pode não ser um erro.
Steve314
1
@ Josh, @ Steve: Há casos em que você deseja ignorar as exceções. Veja este tópico para alguns desses casos.
Home
Uma exceção é um alerta de que algo pode estar errado. Um try..catchbloco vazio é uma coisa; obriga a reconhecer o erro e ignorá-lo deliberadamente; ao jogar pedaços de código sob uma ignição global, podem ocorrer problemas quando essas exceções são lançadas, além de levar a maus hábitos de programação.
Josh K
@ Josh - Acabei de excluir dois comentários porque não estava pensando direito - mas as esperanças são altas para este. Se essa afirmação é global, eu provavelmente concordo - mas parece uma estrutura de blocos para mim. IOW é como um trybloco, exceto que lista as exceções que captura e ignora na frente, em vez de mais tarde. Isso pode até ser uma vantagem de legibilidade - por exemplo, permitir que o leitor saiba que um arquivo ausente não é um erro antes mesmo de ler a chamada em aberto.
precisa saber é o seguinte
1

Ao invés de:

switch(myEnum) {
  case MyEnum.Val1: do1(); ...
  case MyEnum.Val2: do2(); ...
....

Faça o Python, ou agora também o C #:

action = val2func[myEnum]
action()

Scala tem muitos novos recursos.

Finalmente, idiomas como o Clojure podem ser estendidos para fornecer a funcionalidade extra.

Trabalho
fonte
1
C também pode fazer isso. E Pascal. Provavelmente todas aquelas antigas línguas dos anos 70/80/90. Uma matriz de funções se torna uma matriz de ponteiros de função, mas isso não é grande coisa. Onde fica mais fácil é quando você tem funções anônimas - você sabe, como em Lisp, ML, ...
Steve314
Steve314 - correção - este é um exemplo de dicionário que mapeia qualquer valor para uma função. É aqui que as coisas se tornam um pouco mais limpas do que a maioria das coisas dos anos 70/80/90 poderia fazer.
Job
1

Eu tenho duas idéias

Muitas vezes, acho que estou me repetindo em catchblocos. Isso pode ser um pouco ajudado através da extração de métodos, mas isso pode causar confusão desnecessária se os métodos forem muito curtos ou não forem dignos de um método. Então, seria bom aninhar catchblocos:

try {
    // Save something
} catch (Exception e) {
    // Something we do for all Exceptions
    catch (ProcessingException e) {
        // Something we do for all Processing exceptions
        catch (DBExcpetion e) {
            // DBExceptions are a subclass of ProcessingException
        }
        catch (BusinessRuleException e) {
            // BusinessRuleExceptions are also a subclass of ProcessingException
        }
    }
    // Something we do after specific sub class Exceptions
 }

Na programação da web, também me vejo frequentemente fazendo algo assim (este não é um exemplo real, portanto não analise casos de ficção):

Account a = getSavedAccount();
if (a == null) {
    a = getAccountFromSessionId();
}
if (a == null) {
    a = getAccountFromCookieId();
}
if (a == null) {
    a = createNewAccount();
}

Em Javascript (bem, ECMAScript e talvez outros que eu não conheça), já que qualquer valor pode ser avaliado como uma condição, ||pode ajudar.

var a = getAFromLocation1() || getAFromLocation2() || default;

Eu realmente gosto da aparência e desejo que mais idiomas, especialmente alguns do lado do servidor, tenham suporte para isso. (O PHP pode avaliar qualquer coisa como uma condição, mas converte toda a expressão condicional em um booleano em vez de preservar o valor. Não sei sobre Python ou Ruby.) Ele pode ficar complicado depois de três casos, mas se você tiver mais Em três casos, você também pode ter um design de software ruim.

Nicole
fonte
Python faz algo como o seu || avaliação, mas quando finalmente obteve sua x if c else ysintaxe de expressão condicional , um dos principais motivos que aconteceu foi o fato de muitas expressões usarem essa semântica ||e &&serem sutilmente problemáticas. Um caso comum do IIRC era um valor (como zero) válido para o aplicativo que estava sendo tratado false, sendo descartado para que um substituto inválido fosse usado. No entanto - veja minha resposta WRT, a linguagem de programação Icon, que pode ter expressões como get1() else get2() else default.
Steve314
1

O interruptor generalizado disse acima:

 switch(x){
  predicate1:
     dosomething();
  predicate2:
     dosomethingelse();
 }

Em Haskell:

  switch' :: a -> [(a -> Bool, b)] -> b
  switch' a [] = undefined
  switch' a (f,b):xs = if f a
                     then b
                      else switch' a xs

fonte
0

Em C #, eu gostaria de usar simples switch () { ... }, mas extensível com essas expressões:

switch (value)
{
  // string-based operators:
  case begins "Maria": // to catch Maria Carey
    break;
  case ends "Washington": // to catch George Washington
    break;
  case like "ph": // to catch Phil, Phillip, Sophie
    break;
  case between "Aaron" and "April": // to catch all names between
    break;

  // use non-static variables in case expression:
  case Dao.GetDefaultBabyName():
    break;

  // continuable cases without breaking
  case "John":
    bonus = 25;
  case "Peter":
    salary = 500;
    break;

  // jumps between cases
  case "Aleron":
    // do something
    break;
  case "Bella":
    // do something
    jump "Aleron";
    break;

}

E assim por diante. O mesmo com números ou outros tipos (que suportes IComparable, IConvertible...)

Isso pode tornar meu código mais lacônico e legível.

Gênio
fonte
Falhar em casos é um mal conhecido, e geralmente estou bem sem ele. E saltos é GOTOish demais para qualquer programação sã. Mas ter expressões e não estáticas no caso seria uma adição adorável.
CodexArcanum
0

É uma pergunta divertida, como @Macneil disse.

Minha estrutura de controle incomum favorita, que eu (tosse humilde) descobri, é a execução diferencial .

Tem certos usos. Para mim, o uso predominante está na programação de interfaces de usuário, que é uma instância do problema mais geral de manter dados redundantes em correspondência. Por um lado, existem dados do aplicativo e, por outro, há controles da interface do usuário que precisam ser mantidos em concordância. Isso soa como "vinculativo", mas na verdade há muito mais.

Geralmente eu o implico por macros em C ou C ++. Em C #, eu tenho que fazer isso com instruções de expansão manual. Isso é uma dor, mas funciona.

Uma vez eu o implementei em termos de macros Lisp e ficou muito limpo. Não exigiu cuidado por parte do programador. Eu poderia ter feito a mesma coisa em qualquer outra linguagem estruturada se tivesse o cuidado de escrever um analisador completo e depois gerar as coisas certas. Esse é um grande projeto, e eu não o fiz.

Mike Dunlavey
fonte
0

Estruturas de controle "tradicionais", como foro controle do trabalhador, o mantêm subserviente às ideologias corruptas da elite capitalista dominante. É por isso que eu uso estruturas de controle alternativas ph0r. É como for, mas mais radical: você não vai pegar ph0rterno e gravata, jorrando alguns BS corporativos. ph0rmantém real, cara.

Combate o Poder!

j_random_hacker
fonte
0

forLoop mais simples

for(100)
{
    //Will run for 100 times
}


for(i)
{
    //Will run for i times while i must be a positive integer
}


for(i as a)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 0 and 
    //scoped within the loop
}


for(i as a=2)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 2 and 
    //scoped within the loop
}
Gulshan
fonte