Pelo que entendi, conversões implícitas podem causar erros.
Mas isso não faz sentido - as conversões normais também não devem causar erros?
Por que não
len(100)
trabalho pelo idioma interpretando (ou compilando) como
len(str(100))
especialmente porque essa é a única maneira (eu sei) de funcionar. A linguagem sabe qual é o erro, por que não corrigi-lo?
Para este exemplo, usei Python, embora sinta que, para algo tão pequeno, seja basicamente universal.
programming-languages
type-conversion
Quelklef
fonte
fonte
perl -e 'print length(100);'
imprime 3.str
seria a maneira implícita de converter um int em um iterável? que talrange
? oubin
(hex
,oct
) ouchr
(ouunichr
)? Todos esses retornam iteráveis, mesmo questr
pareça o mais óbvio para você nessa situação.Respostas:
Pelo que vale
len(str(100))
,len(chr(100))
elen(hex(100))
são todos diferentes. nãostr
é a única maneira de fazê-lo funcionar, pois há mais de uma conversão diferente no Python de um número inteiro para uma string. Um deles, é claro, é o mais comum, mas não é necessariamente desnecessário dizer que foi o que você quis dizer. Uma conversão implícita significa literalmente "escusado será dizer".Um dos problemas práticos das conversões implícitas é que nem sempre é óbvio qual conversão será aplicada onde houver várias possibilidades, e isso resulta em erros nos leitores ao interpretar o código porque eles não conseguem descobrir a conversão implícita correta. Todo mundo sempre diz que o que eles pretendiam é a "interpretação óbvia". É óbvio para eles, porque é o que eles querem dizer. Pode não ser óbvio para outra pessoa.
É por isso que (na maioria das vezes) o Python prefere explícito ao implícito, prefere não arriscar. O principal caso em que o Python faz a coerção de tipos é na aritmética. Ele permite
1 + 1.0
porque a alternativa seria muito chato viver com, mas ele não permite1 + "1"
, porque ele pensa que você deve ter para especificar se você quer dizerint("1")
,float("1")
,ord("1")
,str(1) + "1"
, ou qualquer outra coisa. Também não permite(1,2,3) + [4,5,6]
, mesmo que possa definir regras para escolher um tipo de resultado, assim como define regras para escolher o tipo de resultado1 + 1.0
.Outros idiomas discordam e têm muitas conversões implícitas. Quanto mais eles incluem, menos óbvios eles se tornam. Tente memorizar as regras do padrão C para "promoções com números inteiros" e "conversões aritméticas comuns" antes do café da manhã!
fonte
len
só pode funcionar com um tipo, é fundamentalmente falha.str
,chr
ehex
todos retornam o mesmo tipo! Eu estava tentando pensar em um tipo diferente cujo construtor pode ter apenas um int, mas ainda não criei nada. Ideal seria um containerX
ondelen(X(100)) == 100
;-)numpy.zeros
parece um pouco obscuro.a == b
,b == c
masa == c
não ser verdade.Está faltando uma palavra: conversões implícitas podem causar erros de tempo de execução .
Para um caso simples como você mostra, é bem claro o que você quis dizer. Mas os idiomas não podem funcionar em casos. Eles precisam trabalhar com regras. Para muitas outras situações, não está claro se o programador cometeu um erro (usando o tipo errado) ou se o programador pretendia fazer o que o código supõe que ele pretendia fazer.
Se o código assumir errado, você receberá um erro de tempo de execução. Como eles são tediosos para rastrear, muitos idiomas erram ao dizer que você errou e deixou que você dissesse ao computador o que realmente queria dizer (corrija o erro ou faça explicitamente a conversão). Outras linguagens adivinham, já que seu estilo se presta a códigos rápidos e fáceis que são mais fáceis de depurar.
Uma coisa a observar é que as conversões implícitas tornam o compilador um pouco mais complexo. Você precisa ter mais cuidado com os ciclos (vamos tentar esta conversão de A para B; oops que não funcionou, mas há uma conversão de B para A! E, em seguida, você também precisa se preocupar com os ciclos de tamanho C e D ), que é uma pequena motivação para evitar conversões implícitas.
fonte
len(100)
voltar3
. Eu acharia muito mais intuitivo calcular o número de bits (ou bytes) na representação de100
.len(100)
deve fornecer a quantidade de caracteres da representação decimal do número 100. Mas isso é realmente uma tonelada de suposições que você está fazendo sem saber deles. Você pode argumentar fortemente por que o número de bits ou bytes ou caracteres da representação hexadecimal (64
-> 2 caracteres) deve ser retornado porlen()
.É possível fazer conversões implícitas. A situação em que você se mete em problemas é quando você não sabe para que lado algo deve funcionar.
Um exemplo disso pode ser visto em Javascript, onde o
+
operador trabalha de maneiras diferentes em momentos diferentes.Se um dos argumentos for uma sequência, o
+
operador é uma concatenação, caso contrário, é adição.Se você recebe um argumento e não sabe se é uma sequência ou um número inteiro, e deseja fazer uma adição a ela, pode ser um pouco confuso.
Outra maneira de lidar com isso é a herança básica (que o perl segue - veja Programação é difícil, vamos usar scripts ... )
No Basic, a
len
função faz sentido apenas ser chamada em uma String (documentos para visual basic : "Qualquer expressão String válida ou nome de variável. Se Expression for do tipo Object, a função Len retornará o tamanho conforme será gravado no arquivo por a função FilePut. ").Perl segue esse conceito de contexto. A confusão que existe em JavaScript com a conversão implícita de tipos para o
+
operador sendo, por vezes, adição e, por vezes, a concatenação não acontece em perl, porque+
é sempre além e.
é sempre concatenação.Se algo é usado em um contexto escalar, é um escalar (por exemplo, usando uma lista como escalar, a lista se comporta como se fosse um número correspondente ao seu comprimento). Se você usar um operador de string (
eq
para teste de igualdade,cmp
para comparação de string), o escalar será usado como se fosse uma string. Da mesma forma, se algo foi usado em um contexto matemático (==
para teste de igualdade e<=>
para comparação numérica), o escalar é usado como se fosse um número.A regra fundamental para toda a programação é "faça o que menos surpreende a pessoa". Isso não significa que não há surpresas, mas o esforço é surpreender a pessoa o mínimo.
Indo para um primo próximo do perl - php, há situações em que um operador pode atuar em algo em contextos de string ou numéricos e o comportamento pode surpreender as pessoas. O
++
operador é um exemplo. Nos números, ele se comporta exatamente como o esperado. Ao atuar em uma sequência, como"aa"
, ela a incrementa ($foo = "aa"; $foo++; echo $foo;
imprimeab
). Também rolará para que,az
quando incrementado, se torneba
. Isso não é particularmente surpreendente ainda.( ideona )
Isso imprime:
Bem-vindo aos perigos de conversões implícitas e operadores agindo de maneira diferente na mesma sequência. (O Perl lida com esse bloco de código de maneira um pouco diferente - ele decide que
"3d8"
quando o++
operador é aplicado é um valor numérico desde o início e passa4
imediatamente ( ideone ) - esse comportamento é bem descrito no perlop: Incremento automático e decremento automático )Agora, por que uma linguagem faz algo de uma maneira e outra faz de outra maneira chega aos pensamentos de design dos designers. A filosofia de Perl é que há mais de uma maneira de fazer isso - e posso pensar em várias maneiras de realizar algumas dessas operações. Por outro lado, o Python tem uma filosofia descrita no PEP 20 - O Zen do Python, que afirma (entre outras coisas): "Deveria haver uma - e de preferência apenas uma - maneira óbvia de fazê-lo".
Essas diferenças de design levaram a diferentes idiomas. Existe uma maneira de obter o comprimento de um número no Python. A conversão implícita vai contra essa filosofia.
Leitura relacionada: Por que Ruby não possui uma conversão implícita de Fixnum em String?
fonte
x
ey
de tal forma um como para produzir uma relação ou a classificação de equivalência, mas operadores de comparação de IIRC Python ...O ColdFusion fez a maior parte disso. Ele define um conjunto de regras para lidar com suas conversões implícitas, tem um único tipo de variável e pronto.
O resultado é anarquia total, onde adicionar "4a" a 6 é 6.16667.
Por quê? Bem, como a primeira das duas variáveis é um número, o resultado será numérico. "4a" é analisado como uma data e visto como "04:00". 04:00 é 04:00 / 24:00, ou 1/6 de um dia (0,16666). Adicione a 6 e você obtém 6.16667.
As listas possuem caracteres separadores padrão de uma vírgula; portanto, se você adicionar um item a uma lista que contenha uma vírgula, basta adicionar dois itens. Além disso, as listas são sequências secretas, para que possam ser analisadas como datas se contiverem apenas 1 item.
A comparação de cadeias verifica se ambas as cadeias podem ser analisadas primeiro para datas. Porque não há tipo de data, faz isso. O mesmo vale para números e cadeias contendo números, notação octal e booleanos ("true" e "yes" etc.)
Em vez de falhar rapidamente e relatar um erro, o ColdFusion manipulará as conversões de tipo de dados para você. E não de um jeito bom.
Obviamente, você pode corrigir as conversões implícitas chamando funções explícitas como DateCompare ... mas depois perde os "benefícios" da conversão implícita.
Para o ColdFusion, essa é uma maneira de ajudar a capacitar os desenvolvedores. Especialmente quando todos esses desenvolvedores estão acostumados a HTML (o ColdFusion trabalha com tags, é chamado CFML, depois eles também adicionam scripts
<cfscript>
, onde você não precisa adicionar tags para tudo). E funciona bem quando você deseja que algo funcione. Mas quando você precisa que as coisas aconteçam de uma maneira mais precisa, você precisa de um idioma que se recuse a fazer conversões implícitas para qualquer coisa que pareça ter sido um erro.fonte
Você está dizendo que conversões implícitas podem ser uma boa idéia para operações que não são ambíguas, como
int a = 100; len(a)
, onde você obviamente deseja converter o int em uma string antes de chamar.Mas você está esquecendo que essas chamadas podem ser sintaticamente inequívocas, mas podem representar um erro de digitação feito pelo programador que pretendia passar
a1
, que é uma string. Este é um exemplo artificial, mas com os IDEs fornecendo preenchimento automático para nomes de variáveis, esses erros acontecem.O sistema de tipos visa nos ajudar a evitar erros e, para idiomas que escolhem a verificação de tipo mais rigorosa, as conversões implícitas prejudicam isso.
Confira os problemas do Javascript com todas as conversões implícitas realizadas por ==, tanto que agora muitos recomendam manter o operador no-implicit-conversion ===.
fonte
Considere por um momento o contexto de sua declaração. Você diz que esse é o "único jeito" de funcionar, mas você tem certeza de que funcionará assim? Que tal isso:
Como outros já mencionaram, em seu exemplo muito específico, parece simples para o compilador intuir o que você quis dizer. Porém, em um contexto maior de programas mais complicados, muitas vezes não é óbvio se você deseja inserir uma string ou digitar um nome de variável para outra ou chamar a função errada ou qualquer uma das dezenas de outros erros lógicos em potencial. .
No caso em que o intérprete / compilador adivinha o que você quis dizer, às vezes funciona magicamente e, outras vezes, você passa horas depurando algo que misteriosamente não funciona sem motivo aparente. É muito mais seguro, no caso médio, saber que a afirmação não faz sentido e gastar alguns segundos corrigindo-a do que você realmente quis dizer.
fonte
Conversões implícitas podem ser uma verdadeira dor de se trabalhar. No PowerShell:
De repente, há o dobro de testes necessários e o dobro de erros que haveria sem conversão implícita.
fonte
Elencos explícitos são importantes, pois eles estão deixando sua intenção clara. Antes de tudo, usar conversões explícitas conta uma história para alguém que está lendo seu código. Eles revelam que você intencionalmente fez o que fez. Além disso, o mesmo se aplica ao compilador. O seguinte é ilegal em C #, por exemplo
O elenco fará com que você perca a precisão, o que pode ser facilmente um bug. Portanto, o compilador se recusa a compilar. Ao usar um elenco explícito, você está dizendo ao compilador: "Ei, eu sei o que estou fazendo." E ele irá: "Ok!" E compilar.
fonte
(X)y
deveria significar é "eu acho que Y é conversível em X; faça a conversão, se possível, ou lance uma exceção, se não"; se uma conversão for bem-sucedida, é possível prever qual será o valor resultante * sem a necessidade de conhecer regras especiais sobre a conversão de um tipoy
para outroX
. Se solicitado a converter -1,5 e 1,5 em números inteiros, alguns idiomas renderiam (-2,1); alguns (-2,2), alguns (-1,1) e outros (-1,2). Embora as regras do C dificilmente são obscurecer ...Os idiomas que suportam conversões / conversões implícitas, ou digitação fraca, como às vezes é referido, farão suposições para você que nem sempre correspondem ao comportamento que você pretendia ou esperava. Os designers do idioma podem ter tido o mesmo processo de pensamento que você teve para um determinado tipo de conversão ou série de conversões e, nesse caso, você nunca verá um problema; no entanto, se não o fizeram, seu programa falhará.
A falha, no entanto, pode ou não ser óbvia. Como essas transmissões implícitas ocorrem em tempo de execução, seu programa será executado felizmente e você verá um problema apenas quando examinar a saída ou o resultado do programa. Uma linguagem que exija conversões explícitas (algumas se referem a isso como digitação forte) causaria um erro antes que o programa iniciasse a execução, o que é um problema muito mais óbvio e mais fácil de corrigir que as conversões implícitas deram errado.
Outro dia, um amigo meu perguntou a ele com 2 anos de idade o que era 20 + 20 e ele respondeu em 2020. Eu disse ao meu amigo: "Ele vai se tornar um programador Javascript".
Em Javascript:
Assim, você pode ver os problemas que os lançamentos implícitos podem criar e por que não é algo que pode ser corrigido. A correção que eu argumentaria é usar moldes explícitos.
fonte