Estou começando isso como um lugar para deixar notas sobre coisas a serem consideradas ao verificar a consistência da API no Julia 1.0.
[x] Priorização da convenção. Listar e priorizar nossas convenções do que vem primeiro em termos de argumentos de função para blocos do, argumentos de IO para funções que imprimem, saídas para funções no local etc. (https://github.com/JuliaLang/julia/issues/ 19150).
[] Argumentos posicionais vs palavras-chave. Há muito tempo não tínhamos argumentos de palavra-chave. Às vezes, eles ainda são evitados por questões de desempenho. Devemos fazer essa escolha com base no que constitui a melhor API, não nesse tipo de bagagem histórica (problemas de desempenho de palavras-chave também devem ser resolvidos para que isso não seja mais levado em consideração).
[] Ferramentas de metaprogramação. Temos várias ferramentas como @code_xxx
que são combinadas com funções subjacentes como code_xxx
. Eles devem se comportar de forma consistente: assinaturas semelhantes, se houver funções com assinaturas semelhantes, certifique-se de que tenham versões de macro semelhantes. O ideal é que todos eles retornem valores, em vez de alguns retornando valores e outros imprimindo resultados, embora isso possa ser difícil para coisas como código LLVM e código assembly.
Equivalência de nome de arquivo []
[] APIs de redutores. Certifique-se de que os redutores tenham comportamentos consistentes - todos usam uma função de mapa antes da redução; argumentos de dimensão congruente, etc.
[] Argumentos de dimensão. Tratamento consistente de argumentos de entrada "calcular através desta [estas] dimensão [s]", quais tipos são permitidos etc, considere se fazer isso como argumentos de palavra-chave pode ser desejado.
[] Pares mutantes / não mutantes. Verifique se as funções não mutantes estão emparelhadas com funções mutantes onde faz sentido e vice-versa.
[] Tupla vs. vararg. Verifique se há consistência geral entre as funções tomarem uma tupla como o último argumento ou um vararg.
[] Uniões vs. anuláveis vs. erros. Regras consistentes sobre quando as funções devem lançar erros e quando devem retornar Nullables ou Unions (por exemplo, parse / tryparse, match, etc.).
[] Apoie geradores o mais amplamente possível. Certifique-se de que qualquer função que possa funcionar sensatamente com geradores o faça. Já estamos muito bem sobre isso, mas acho que perdemos alguns.
[] Seleção do tipo de saída. Seja consistente sobre se as APIs de "tipo de saída" devem ser em termos de tipo de elemento ou tipo geral de contêiner (ref # 11557 e # 16740).
[x] Escolha um nome. Existem algumas funções / operadores com aliases. Acho que isso é adequado nos casos em que um dos nomes não é ASCII e a versão ASCII é fornecida para que as pessoas ainda possam escrever código ASCII puro, mas também há casos como <:
que é um apelido para issubtype
onde ambos os nomes são ASCII. Devíamos escolher um e descontinuar o outro. Substituímos is
em favor de ===
e devemos fazer o mesmo aqui.
[] Consistência com DataStructures . Está um pouco além do escopo do Base Julia, mas devemos ter certeza de que todas as coleções em DataStructures têm APIs consistentes com aquelas fornecidas pelo Base. A conexão na outra direção é que alguns desses tipos podem informar como acabamos projetando as APIs no Base, já que queremos que elas se estendam de maneira uniforme e consistente.
[] NaNs vs. DomainErrors. Consulte https://github.com/JuliaLang/julia/issues/5234 - tenha uma política para quando fazer isso e certifique-se de que seja seguida de forma consistente.
[] Gerador de coleção <=>. Às vezes você quer uma coleção, às vezes quer um gerador. Devemos examinar todas as nossas APIs e nos certificar de que haja uma opção para ambas quando fizer sentido. Era uma vez, havia uma convenção para usar um nome em maiúsculas para a versão do gerador e um nome em minúsculas para a versão que está ansiosa e retorna uma nova coleção. Mas ninguém nunca prestou atenção a isso, então talvez precisemos de uma nova convenção.
[] Funções de ordem superior em associativos. Atualmente, algumas funções de ordem superior iteram sobre coleções associativas com assinatura (k,v)
- por exemplo, map
, filter
. Outros iteram sobre pares, ou seja, com a assinatura kv
, exigindo que o corpo desestruture explicitamente o par em k
e v
- por exemplo, all
, any
. Isso deve ser revisado e tornado consistente.
[x] Converter vs. construir. Permita a conversão quando apropriado. Por exemplo, houve vários problemas / dúvidas sobre convert(String, 'x')
. Em geral, a conversão é apropriada quando há uma única transformação canônica. A conversão de strings em números em geral não é apropriada porque existem muitas maneiras textuais de representar números, então precisamos analisar em vez disso, com opções. Há uma única maneira canônica de representar os números de versão como strings, portanto, podemos convertê-los. Devemos aplicar essa lógica cuidadosa e universalmente.
[] Revise a integridade da API de coleções. Devemos olhar para as funções de biblioteca padrão para coleções fornecidas por outras linguagens e ter certeza de que temos uma maneira de expressar as operações comuns que elas possuem. Por exemplo, não temos uma função flatten
ou uma função concat
. Provavelmente deveríamos.
[] Auditoria de sublinhado.
Pedimos desculpas se este não for o lugar apropriado para mencionar isso, mas seria bom ser mais consistente com sublinhados em nomes de função daqui para frente.
Não, este é um bom lugar para isso. E sim, devemos nos esforçar para eliminar todos os nomes onde os sublinhados são necessários :)
Para o segundo ponto de @tkelman , consulte https://github.com/JuliaLang/julia/issues/19150
Também houve um Julep recente sobre a API para find
e funções relacionadas: https://github.com/JuliaLang/Juleps/blob/master/Find.md
Devemos descontinuar put!
e take!
nos canais (e talvez fazer o mesmo para os futuros), uma vez que temos push!
e shift!
neles? Apenas sugerindo a remoção de 2 palavras redundantes na API.
Suspeito que shift!
seja amigável. Um candidato é fetch!
nós já temos fetch
que é a versão não mutante de take!
ref # 13538 # 12469
@amitmurthy @malmaud
Editar: faria até sentido reutilizar send
e recv
nos canais. (Estou surpreso que eles sejam usados apenas para UDPSockets no momento)
+1 para substituir put!
/ take!
por push!
/ fetch!
Adicionarei a renomeação de @inferred
a @test_inferred
.
Verifique novamente se as especializações são consistentes com as funções mais genéricas, ou seja, não algo como # 20233.
Revise todas as funções exportadas para verificar se alguma pode ser eliminada, substituindo-as por envio múltiplo, por exemplo, print_with_color
O emparelhamento típico é push!
e shift!
ao trabalhar com uma estrutura de dados do tipo fila.
Se não formos usar o emparelhamento de nomes típico para este tipo de estrutura de dados porque estamos preocupados que a operação acarrete sobrecarga de comunicação que não é transmitida adequadamente por esses nomes, então não acho que push!
faz sentido. send
e recv
realmente podem ser melhores.
Verifique novamente se há consistência geral entre as funções tomarem uma tupla como o último argumento ou um vararg.
Talvez muito grande para este problema, mas seria bom ter regras consistentes sobre quando as funções devem lançar erros e quando devem retornar Nullable
s ou Union
s (por exemplo, parse
/ tryparse
, match
, etc.)
Nenhum problema muito grande, @simonbyrne - esta é a lista de lavanderia.
Btw: isso não é realmente para mudanças específicas (por exemplo, renomear funções específicas) - é mais sobre tipos de coisas que podemos revisar. Para alterações propostas específicas, basta abrir um exemplar propondo essa alteração.
Temos muitas ferramentas como @code_xxx que são emparelhadas com funções subjacentes como code_xxx
Não tenho certeza se é disso que você está falando, mas consulte CreateMacrosFrom.jl
Documente todas as funções exportadas (incluindo doctests)
se isso faz parte disso, então talvez também: lembre-se de rotular seus testes com o número do problema / pr. Isso torna muito mais fácil entender por que esse teste existe. Eu sei como o git blame funciona, mas ao adicionar conjuntos de testes (só para dar um exemplo), às vezes é um pouco um mistério o que está sendo testado e seria ótimo se o número do problema / pr sempre estivesse lá.
@dpsanders : e macros exportadas! por exemplo, @fastmath
não tem docstring.
Isso é muito pequeno, mas as funções string
e Symbol
fazem quase a mesma coisa e têm capitalização diferente. Acho que symbol
faria mais sentido.
@amellnik A diferença é que Symbol
é um construtor de tipo e string
é uma função regular. O IIRC tínhamos symbol
mas foi substituído em favor do construtor de tipo. Não estou convencido de que uma mudança seja necessária para isso, mas acho que devemos usar o construtor String
no lugar de string
.
se houver alguma coisa, acho que devemos usar o construtor String no lugar da string.
Não, são funções diferentes e não devem ser mescladas
julia> String(UInt8[])
""
julia> string(UInt8[])
"UInt8[]"
Não, são funções diferentes e não devem ser mescladas
Isso parece uma situação em que string(args...)
deveria ser substituído em favor de sprint(print, args...)
, então - ter string
e String
é confuso. Poderíamos nos especializar em sprint(::typeof(print), args...)
para recuperar qualquer desempenho perdido. Junto com essas linhas, também pode fazer sentido suspender repr(x)
por sprint(showall, args...)
.
Isso parece normal, embora chamar string
para transformar algo em uma string pareça bastante normal ....
chamar string para transformar algo em uma string parece bastante padrão
Sim, mas é aí que entra a desconexão entre String
e string
.
sprint(print, ...)
parece redundante. Se nos livrarmos de string
, podemos renomear sprint
para string
e obteremos string(print, foo)
e string(showall, foo)
que parece bom em minha opinião .
Este pode ser um caso em que a consistência é superestimada. Eu acho que é bom ter string(x)
para "apenas me dê uma representação de string de x". Se for mais complicado do que isso, por exemplo, exigir que você especifique qual função de impressão usar, então usar outro nome como sprint
faz sentido.
Também não haveria problema em renomear String(UInt8[])
para outra coisa e usar String
vez de string
. string
nos dá um pouco mais de flexibilidade no futuro para alterar o tipo de string que retornamos, mas isso não parece provável de acontecer.
reinterpret(String, ::Vector{UInt8}
faz algum sentido ou é um trocadilho com reinterpret
?
Isso parece fazer sentido.
Um problema é que esta função às vezes está copiando, então esse nome pode ser um tanto enganoso.
É verdade, mas as strings devem ser imutáveis, então provavelmente podemos nos safar com isso.
Também existe um método String(::IOBuffer)
, mas parece que ele pode ser descontinuado para readstring
.
Também pensei em sua proposta de alteração de API, mas a interface de string(a, b...)
é que ela codifica e concatena seus argumentos, e isso seria uma exceção irritante para primeiros argumentos que podem ser chamados. Se removermos a concatenação de string
, ela poderá funcionar.
Sim combinado; consistência e evitar pegadinhas é o mais importante.
Observando os problemas # 18326 e # 3893 na categoria "argumentos de dimensão".
Se eu puder acrescentar outro item: certificar-se de que o comportamento dos recipientes de mutáveis seja documentado e consistente.
@ JaredCrean2 : você pode explicar o que você quer dizer com isso?
Eu certamente espero que não envolva fazer muitas "cópias defensivas".
Por exemplo, se eu tenho uma matriz de tipos mutáveis e chamo sort
nela, a matriz retornada aponta para os mesmos objetos da matriz de entrada ou copia os objetos e faz com que a matriz retornada aponte para eles?
Os mesmos objetos. Tenho certeza de que todos os nossos métodos de classificação, getindex, filtragem, pesquisa, etc. de coleção seguem esta regra, não?
Não acho que falte clareza ou consistência nesse ponto - são sempre os mesmos objetos.
Na verdade, acho que a única função padrão em que esse não é o caso é deepcopy
onde o objetivo é obter todos os objetos novos.
Isso está documentado em algum lugar?
Não - poderíamos, mas não tenho certeza de onde seria melhor documentá-lo. Por que as funções fariam cópias desnecessariamente? De onde você teve a impressão de que sim?
Olá. Eu não vi nenhum comentário sobre serialização de dados.
Mais cedo ou mais tarde, os programas julia serão escritos e executados publicamente, os dados começarão a estratificar às vezes, durante anos. Serialização de dados, por exemplo. a cadeia: objeto para bytes orientado por tipo (talvez sobre json ou ...) deve ser construída para ser resistente ao tempo. Pensar em versionamento semântico e API da web também pode contar.
Podemos esperar que a serialização dos dados do usuário fique próxima a https://github.com/JuliaLang/julia/blob/v0.5.1/base/serialize.jl ?
Por que as funções fariam cópias desnecessariamente? De onde você teve a impressão de que sim?
Eu não sei se eles fazem ou não. Pelo que eu posso dizer, o comportamento é indefinido. Pelo comentário de @JeffBezanson , há pessoas que defendem a realização de cópias defensivas, às quais ele se opõe. Portanto, a documentação deve abordar a questão das cópias defensivas em algum lugar.
Você parece estar sugerindo algum tipo de princípio de ação mínima, mas dependendo dos detalhes do algoritmo, o que é a "ação mínima" fica ambíguo. Para obter consistência na API, acho que orientações mais específicas são necessárias.
@ o314 : este é um problema de revisão de consistência da API, não tenho certeza de como a serialização está relacionada.
@ JaredCrean2 : se o objeto de nível superior é copiado ou não, certamente precisa ser documentado. O que estou dizendo é que objetos mais profundos nunca são copiados, exceto por deepcopy (obviamente).
O que estou dizendo é que objetos mais profundos nunca são copiados, exceto por deepcopy (obviamente).
Houve uma discussão recente sobre isso no contexto de copy
para alguns dos wrappers de array, por exemplo, SubArray
e SparseMatrixCSC
mas também Symmetric
, LowerTriangular
. Parece-me que, de acordo com a política mencionada acima, copy
seria um noop para esses tipos de invólucro. A política que você mencionou é o nível certo de abstração aqui? Por exemplo, eu acho que isso implica que se Array
s foram implementados em Julia (envolvendo um buffer), o comportamento de copy
em Array
s deve então mudar para um noop.
Se a convenção é que objetos mais profundos nunca são copiados, então tudo o que resta é documentá-los. A documentação é uma parte realmente importante de uma API. Esse comportamento pode parecer óbvio para você (talvez porque você escreveu partes do código), mas de uma perspectiva externa não é tão óbvio.
Edit: não vi a postagem de Andreas. Essa é uma consideração interessante.
@StefanKarpinski Eu concordo com seu ponto.
E todos os tópicos principais invocados aqui são muito bons e inteligentes.
Mas às vezes tenho um pouco de medo em relação ao equilíbrio entre processo e dados em Julia:
Podemos chamar fortran ou c facilmente com certeza,
Mas o código será implantado com a mesma facilidade em um datacenter moderno, por exemplo. aws lambda com sua função como padrão de serviço. o código será facilmente chamado pela Internet, API aberta?
Às vezes, é necessário reduzir a carga funcional para escalar (sem genérico, sem vaargs na assinatura da função, sem alta ordem na API pública) e vincular mais sistematicamente os dados (esquema json / openapi).
Eu vi algumas bibliotecas python muito boas afundando assim e isso é uma pena.
Acho que é um ponto crucial para uma linguagem 1.0 manter os dados e funções balanceados e modulares para ser capaz de implantar facilmente na web. E, para esta função, a interface deve ser menos orientada para animais de estimação e mais para gado quando necessário.
Pode ser que esse não seja o ponto neste tópico.
@StefanKarpinski Posso ter entendido mal sua postagem. Quando você disse
se o objeto de nível superior é copiado ou não certamente precisa ser documentado
o que significa "objeto de nível superior"? Se eu tiver x::Vector{MyMutableType}
, o objeto de nível superior é x
ou os elementos de x
?
O objeto de nível superior se refere ao próprio x
, não aos elementos de x
.
@andreasnoack A noção de objeto de nível superior deve se referir à estrutura abstrata implementada, não aos detalhes de implementação.
talvez adicionar float
e outras funções semelhantes que atuam tanto em tipos quanto em valores?
Revendo as notas de versão 0.6, parece estranho que iszero(A::Array{T})
seja introduzido, enquanto muitas outras funções (por exemplo, sumabs
, isinteger
, isnumber
) sobre matrizes são preterido em favor de all(f,A)
.
Existem zero matrizes e são zero elementos em seu espaço vetorial. iszero
testa genericamente se algo é o inverso aditivo, o que matrizes zero são.
Ré. consistência de sublinhados em nomes de função, aqui está uma localização atual para count_ones
e count_zeros
.
Parece-me que se você quiser manter a API Julia consistentemente consistente, você precisará ter algum software que permita (a) especificar quais são as regras / convenções da API, (b) realizar análise estática do código Julia para detectar desvios dessas regras / convenções e (c) oferecer sugestões. Essa ferramenta beneficiaria tanto Julia Base quanto todos os Pacotes Julia. Um novo pacote de Julia pode resolver o problema. (Língua de mau humor: a primeira coisa que este pacote deve fazer é sugerir seu próprio nome; APICheck.jl, ApiCheck.jl, API_Check.jl, APIChecker.jl, JuliaAPIChecker.jl, etc.) Eu sou bastante novo para Julia, então não quero assumir a liderança em tal coisa. No entanto, eu não me importaria de contribuir. Alguma sugestão de como fazer isso?
Adoraríamos ter isso no Lint.jl!
num2hex
e hex2num
(# 22031 e # 22088)
Eu também acredito que Lint.jl é o pacote certo para verificação de consistência da API Julia. Mas se formos por esse caminho, a lista original de Stefan deve ser muito mais precisa. Por exemplo, quando ele escreve "devemos ter certeza de que todas as coleções em DataStructures têm APIs consistentes", as perguntas que vêm à mente são:
Para gerenciar tais inventários e análises, podemos querer adicionar um projeto ao repositório Julia (projeto # 8), ou ao repositório JuliaPraxis (sugerido offline pelo TotalVerb) ou ao repositório Lint. Nesse caso, precisaríamos decidir quem seria o proprietário de tal projeto, quais pessoas deveriam estar envolvidas desde o início e quem deveria tomar as decisões finais sobre o que as convenções de Julia realmente são (para fins de linting).
Mas antes de avançar mais nessas linhas, gostaria de perguntar a @StefanKarpinski : quais são suas idéias sobre como trabalhar sua lista de problemas de consistência da API Julia?
Concordo que especificar isso especificamente é uma boa ideia. Descobrir o que essa lista deve ser faz parte do trabalho aqui - se você quiser dar uma olhada nisso, seria ótimo.
Nós realmente precisamos de um Base.datatype_module e um Base.function_module?
Uma função unificada "módulo" (talvez getmodule) despachando em tipo de dados e função parece mais consistente para mim.
E os sublinhados em @code_typed
e amigos?
Essa é uma boa oportunidade para refatorar (a razão declarada para a proibição do sublinhado). Você poderia ter uma macro @code
com o primeiro argumento sendo o tipo de código que você deseja.
( @bramtayl , lembre-se de colocar crases em torno das macros, pois isso envia um ping para o "código" do usuário do github, se não; @code
)
FWIW, o preenchimento da guia só funciona com nomes de funções. Ser capaz de fazer @code_<TAB>
é bom ....
Se a refatoração for considerada, mas rejeitada, então se há ou não sublinhados é discutível, porque o único ponto da proibição do sublinhado é encorajar a refatoração. Na verdade, nesse caso, parece que sublinhados devem ser incentivados para tornar a linguagem mais clara
Auditoria de sublinhado.
contra-proposta: ainda auditamos esses nomes, mas, em vez disso, adicionamos mais sublinhados onde isso tornaria o código mais fácil de ler (codetyped vs code_typed, isos2 vs is_os2).
Não sou absolutista quanto a isso. Acho que code_typed
está bem, é útil completar a tabulação como
Para mim, parece que o navio navegou ao adicionar mais sublinhados, já que teríamos que desativar basicamente metade da Base. Como exemplo, existem 74 funções de predicado que começam com is
e apenas 6 que começam com is_
. O que faz mais sentido, desaprovar 6 ou 74?
Ok, há vários objetivos conflitantes aqui:
1) Tornando os nomes mais legíveis
2) Reduzindo a rotatividade de código
3) Encorajar a refatoração
A eliminação de sublinhados pela colisão de palavras falha em todas as três frentes.
Que show
métodos que aceitam um fluxo não são !
terminados parece inconsistente com a convenção usual? Ref. https://github.com/JuliaLang/julia/pull/22604/commits/db9d70a279763ded5088016d9c3d4439a49e3fca#r125115063. Melhor! (Editar: suponho que corresponda aos métodos write
que aceitam um fluxo.)
Existem inconsistências com a API de características. Alguns traços são calculados chamando o traço como
TypeArithmetic(Float64)
enquanto outras, esta função deve ser escrita em letras minúsculas:
iteratorsize(Vector{Float64})
Considere renomear size
-> shape
(xref # 22665)
Array{T,1}()
provavelmente também deve ser descontinuado:
julia> Array{Int,1}()
0-element Array{Int64,1}
julia> Array{Int,2}()
WARNING: Matrix{T}() is deprecated, use Matrix{T}(0, 0) instead.
Tenho pensado em coleções. Basicamente, temos três tipos:
k=>v
pares.Tornei-me cético em relação ao comportamento do tipo dict. O canário na mina de carvão é map
, onde operar em pares de valores-chave não é natural, já que você geralmente não deseja alterar o conjunto de chaves. Também é possível que arrays e dicts implementem a mesma interface:
keys
corresponde a eachindex
mapindexed
e filterindexed
seriam úteis para dicts e arrays. Eles são como mapear e filtrar, mas também passam para sua função o índice do item em questão.pairs
, que é basicamente um atalho para zip(keys(c), values(c))
.Considere renomear ind2sub
e sub2ind
, que são matlabismos aparentemente, e que têm um nome não juliano e estranho para um usuário não matlab. Os nomes possíveis seriam indice
e linearindice
respectivamente. Não me atrevi a fazer uma RP porque não tenho certeza do que as pessoas pensam sobre isso, mas farei se houver apoio.
Mesma coisa com rad2deg
e deg2rad
.
Ref. # 22791 ( select
-> partialsort
). Melhor!
Uma coisa que não vi aqui: os argumentos posicionais opcionais vêm primeiro ou por último? Às vezes, os argumentos posicionais opcionais vão primeiro, como em sum(f, itr)
e rand([rng,] ..)
. Mas para outro lugar eles vão por último, por exemplo, em median(v[, region])
ou split(s::AbstractString[, chars])
. Às vezes, eles podem ir primeiro ou por último, mas não os dois! (Por exemplo, mean
pode assumir uma função primeiro ou uma dimensão por último, mas não ambos.)
A semântica da linguagem atual força os argumentos opcionais a irem por último: você pode escrever f(a, b=1)
mas não f(b=1, a)
. Mas se todos os argumentos opcionais forem por último, o que acontece com os blocos convenientes do?
Se nada mais, é uma pequena verruga que a linguagem tem de definir métodos como tal, de rand.jl
: shuffle!(a::AbstractVector) = shuffle!(GLOBAL_RNG, a)
. A sintaxe do argumento posicional opcional deve cuidar exatamente desse caso de uso.
Talvez devesse ir em uma edição separada, mas parece possível mover os argumentos opcionais para onde você quiser. Assim, por exemplo, f(a = 1, b, c = 2)
definiria f(x) = f(1, x, 2)
e f(x, y) = f(x, y, 2)
xref # 22460 para uma tentativa (impopular) de habilitar argumentos padrão em qualquer posição.
Talvez renomear warn
para warning
(matlab também usa isso), não é grande coisa, mas pensei em mencionar?
Eu gosto de warn
porque é um verbo, como throw
.
Eu fiquei muito confuso com isso:
julia> f(;a=1,b=1) = a+b
f (generic function with 1 method)
julia> f(a=4,5) # I intended to write f(a=4,b=5)
ERROR: MethodError: no method matching f(::Int64; a=4)
Closest candidates are:
f(; a, b) at REPL[13]:1
Eu sugiro apenas permitir palavras-chave por último ao chamar funções, semelhante a ao definir funções de palavra-chave.
Eu sugiro apenas permitir palavras-chave por último ao chamar funções, semelhante a ao definir funções de palavra-chave.
Existem muitas APIs em que passar palavras-chave em outras posições é útil e ergonômico.
Por curiosidade, existe uma ordem de avaliação definida para argumentos posicionais e de palavras-chave? Vi alguns problemas mais antigos e https://docs.julialang.org/en/latest/manual/functions/#Evaluation -Scope-of-Default-Values-1 fala sobre escopos, mas nada que encontrei indica se, por exemplo, os argumentos são avaliados da esquerda para a direita, ou todos os argumentos posicionais são avaliados antes de todos os argumentos de palavra-chave, ou se não houver uma ordem de avaliação definida (ou outra coisa).
@yurivish , para palavras-chave, consulte os documentos (também https://github.com/JuliaLang/julia/issues/23926). Para opcionais a história é um pouco mais complicada, talvez leia aqui . (Observe, porém, que as perguntas são mais bem feitas em https://discourse.julialang.org/)
Não parece valer a pena, mas sempre me parece estranho que bits(1)
retorne um String
, parece que deveria ser BitVector
ou Vector{Bool}
.
Eu gostaria de sugerir uma revisão das tabelas de métodos que despacham em Function
ou Callable
. Vamos tentar ter certeza de que essas APIs são do jeito que queremos ... e que não estamos perdendo a oportunidade de permitir a reestruturação das tabelas de forma que possamos permitir a chamada de pato de qualquer objeto.
Quanto a all
e any
, eles parecem simples de depreciar para all(f(x) for x in xs)
, que já está eta reduzido para all(Generator(f, xs))
e, portanto, não deve ter despesas indiretas.
Não tenho certeza se é o que você quis dizer, mas achei que vale a pena afirmar apenas no caso: sou totalmente contra a depreciação de qualquer API de estilo funcional para geradores. Temos any(f, x)
e all(f, x)
e eles são amplamente usados; -10000000 para remover esses (ou quaisquer métodos, na verdade).
Im gerador profissional. Parece um bloco de construção fundamental da programação preguiçosa e deve ser exportado. all(Generator(f, xs))
às vezes mais conveniente para funções definidas do que all(f(x) for x in xs)
. Também +10000000 para restaurar o equilíbrio
Eu prefiro ter menos sintaxe aqui, se possível. Se for fácil, legível e eficaz expressar a ideia de "tomar xs, aplicar f a tudo e retornar verdadeiro se todos forem verdadeiros", então por que deveríamos colocá-lo em um verbo?
Se a preocupação for o substantivo desnecessário x
em f(x) for x in xs
, então a sugestão de @bramtayl de exportar Generator
(talvez usando um nome melhor como Map
?) faz sentido.
Coisas como all(isnull, x)
são bem mais simples do que all(isnull(v) for v in x)
. Substituímos a função allnull
de NullableArrays em favor de all(isnull, x)
; se essa sintaxe fosse embora, provavelmente teríamos que reintroduzi-la.
Que tal renomear strwidth
para stringwidth
(acho que esta é a única função de manipulação de string exportada que abreviou string para str)
Na verdade, ele foi renomeado para textwidth
(https://github.com/JuliaLang/julia/pull/23667).
IMO, este problema é muito amplo para ter o marco 1.0 nele, visto que queremos obter o congelamento de recursos em breve. Podemos precisar de vários proprietários e atribuir conjuntos de funções para revisão se quisermos fazer isso.
Além disso, este é outro lugar onde o FemtoCleaner pode atualizar automaticamente muitas coisas após a 1.0, mesmo que seja bom fazer tudo certo.
apenas um comentário sobre a largura do texto:
INFO: Testing Cairo
Test Summary: | Pass Total
Image Surface | 7 7
Test Summary: | Pass Total
Conversions | 4 4
Test Summary: | Pass Total
TexLexer | 1 1
WARNING: both Compat and Cairo export "textwidth"; uses of it in module Main must be qualified
Samples : Error During Test
Got an exception of type LoadError outside of a <strong i="6">@test</strong>
LoadError: UndefVarError: textwidth not defined
Stacktrace:
[1] include_from_node1(::String) at .\loading.jl:576
[2] include(::String) at .\sysimg.jl:14
[3] macro expansion at C:\Users\appveyor\.julia\v0.6\Cairo\test\runtests.jl:86 [inlined]
[4] macro expansion at .\test.jl:860 [inlined]
[5] anonymous at .\<missing>:?
[6] include_from_node1(::String) at .\loading.jl:576
[7] include(::String) at .\sysimg.jl:14
[8] process_options(::Base.JLOptions) at .\client.jl:305
[9] _start() at .\client.jl:371
while loading C:\Users\appveyor\.julia\v0.6\Cairo\samples\sample_pango_text.jl, in expression starting on line 28
A mensagem de erro parece bastante clara sobre qual é o problema? Cairo
precisa estender o método base.
help?> Base.textwidth
No documentation found.
Binding Base.textwidth does not exist.
julia> versioninfo()
Julia Version 0.6.0
julia> Compat.textwidth
textwidth (generic function with 2 methods)
Não tive dúvidas de que a mensagem (que recebi via travis) está OK, mas por que o Compat exporta a largura de texto se não está em 0,6?
Porque esse é o objetivo do Compat? Esta discussão está saindo muito do escopo, então eu sugiro que possamos continuar com o discurso ou com folga.
Eu sugiro mudar copy
para shallowcopy
e deepcopy
para copy
, pois recentemente demorei bastante para perceber que a cópia é uma cópia "superficial" e que função que escrevi estava alterando o array de arrays. Acho que seria muito mais intuitivo se copy
fizesse uma cópia "profunda" e algo como shallowcopy
fosse usado para cópias rasas? Eu sei agora quando usar deepcopy
, mas acho que muitos outros usuários terão o mesmo problema.
Por favor, vamos tentar manter este problema para a consistência da API, não um monte de "coisas específicas que eu não gosto".
Associative
o nome parece bastante inconsistente com todos os outros nomes de tipo em Julia.
Em primeiro lugar, os tipos geralmente não são adjetivos. O substantivo é Association
, e é usado pelo menos por alguns documentos do Mathematica que encontrei.
Acho que AbstractDict
seria muito mais consistente com outros tipos como AbstractArray
, AbstractRange
, AbstractSet
e AbstractString
, cada um dos quais um concreto prototípico tipifica Dict
, Array
, Range
, Set
e String
.
Nossos tipos de exceção estão um pouco espalhados: alguns são nomeados FooError
, outros são nomeados BarException
; alguns são exportados, a maioria não. Isso poderia usar uma passagem para consistência.
Então, o que seria preferido, FooError
ou BarException
? Exportado ou não?
Para mim, BarException
envolve em algum lugar um padrão de aumentar / pegar.
Eu prefiro muito, e alguns outros no mundo funcional também, use o padrão Some
/ None
(*) onde o fluxo de controle é mais direto e previsível.
Então, +1 por FooError
(*) Some
/ Void
ex Optional
em julho # 23642.
Essas coisas ainda estão sobre a mesa devido ao congelamento de recursos? Eu gostaria especialmente de lidar com argumentos opcionais versus argumentos de palavra-chave, mas a lista de funções com vários argumentos opcionais (o caso mais claro para usar argumentos de palavra-chave) é muito longa.
Por favor dê uma olhada! Não tive a chance de examinar essas questões sistematicamente.
BTW, notei uma inconsistência na nomenclatura dos traços: temos iteratorsize
, iteratoreltype
, mas IndexStyle
, TypeRangeStep
, TypeArithmetic
e TypeOrder
. Parece que as variantes do CamelCase são mais numerosas e mais recentes, então talvez devêssemos adotar essa convenção em todos os lugares?
Isso definitivamente deve ser consistente. Você quer fazer um PR?
Acho que isso deve ser corrigido como parte de https://github.com/JuliaLang/julia/pull/25356.
EDITAR: veja também https://github.com/JuliaLang/julia/issues/25440
Isso é feito principalmente ou pode ser feito em versões 1.x. Posso atualizar as caixas de seleção, mas acabamos de examiná-las na chamada de triagem e tudo, exceto o # 25395 e a auditoria de sublinhado, está concluída.
A seguir está uma análise de todos os símbolos exportados do Base que contêm sublinhados, não são reprovados e não são macros de string. O principal a ser observado aqui é que esses são apenas nomes exportados; isso não inclui nomes não divulgados que pedimos às pessoas que chamem de qualificados.
Separei as coisas por categoria. Esperançosamente, isso é mais útil do que irritante.
Temos as seguintes macros com funções correspondentes:
@code_llvm
, code_llvm
@code_lowered
, code_lowered
@code_native
, code_native
@code_typed
, code_typed
@code_warntype
, code_warntype
Qualquer alteração aplicada às macros, se houver, deve ser aplicada de forma semelhante às funções.
module_name
-> nameof
(# 25622)module_parent
-> parentmodule
(# 25629, consulte # 25436 para uma tentativa anterior de renomeação)method_exists
-> hasmethod
(# 25615)object_id
-> objectid
(# 25615)pointer_from_objref
pointer_from_objref
talvez pudesse usar um nome mais descritivo, talvez algo como address
?
Os aliases de tipo contendo sublinhados são C_NULL
, Cintmax_t
, Cptrdiff_t
, Csize_t
, Cssize_t
, Cuintmax_t
e Cwchar_t
. Aqueles que terminam em _t
devem permanecer, pois são nomeados para serem consistentes com seus tipos C correspondentes.
C_NULL
é o estranho aqui, sendo o único alias C contendo um sublinhado que não é espelhado em C (já que em C isso é apenas NULL
). Poderíamos considerar isso CNULL
.
C_NULL
count_ones
count_zeros
trailing_ones
trailing_zeros
leading_ones
leading_zeros
Para uma discussão sobre como renomeá-los, consulte # 23531. Eu defendo a remoção dos sublinhados para estes, bem como algumas das substituições propostas nesse PR. Acho que deve ser reconsiderado.
unsafe_copyto!
unsafe_load
unsafe_pointer_to_objref
unsafe_read
unsafe_store!
unsafe_string
unsafe_trunc
unsafe_wrap
unsafe_write
Provavelmente não há problema em mantê-los como estão; a feiura do sublinhado ressalta ainda mais sua insegurança.
broadcast_getindex
broadcast_setindex!
to_indices
Aparentemente, broadcast_getindex
e broadcast_setindex!
existem. Eu não entendo o que eles fazem. Talvez eles pudessem usar um nome mais descritivo?
Curiosamente, a versão de índice único de to_indices
, Base.to_index
, não é exportada.
catch_backtrace
catch_stacktrace
-> stacktrace(catch_backtrace())
(# 25615)Presumivelmente, esses são os catch
equivalentes em bloco de backtrace
e stacktrace
, respectivamente.
current_task
task_local_storage
disable_sigint
reenable_sigint
process_exited
process_running
redirect_stderr
redirect_stdin
redirect_stdout
nb_available
-> bytesavailable
(# 25634)Seria bom ter uma função de redirecionamento IO
-> IO
mais geral na qual todos eles pudessem ser combinados, por exemplo, redirect(STDOUT, io)
, removendo assim tanto sublinhados quanto exportações.
promote_rule
promote_shape
promote_type
Veja # 23999 para uma discussão relevante sobre promote_rule
.
print_with_color
-> printstyled
(consulte # 25522)print_shortest
(consulte # 25745)escape_string
(consulte # 25620)unescape_string
escape_string
e unescape_string
são um pouco estranhos porque podem imprimir em um stream ou retornar uma string. Veja # 25620 para uma proposta para mover / renomear estes.
include_dependency
include_string
include_dependency
. Isso é usado fora da Base? Não consigo pensar em uma situação em que você desejaria isso em vez de include
em qualquer cenário típico.
include_string
. Esta não é apenas uma versão oficialmente sancionada de eval(parse())
?
gc_enable
-> GC.enable
(# 25616)get_zero_subnormals
set_zero_subnormals
time_ns
get_zero_subnormals
e set_zero_subnormals
poderiam ser usados com nomes mais descritivos. Eles precisam ser exportados?
+1 para method_exists => methodexists
e object_id => objectid
. Também é meio bobo que catch_stacktrace
exista. Ele pode ser reprovado de acordo com sua definição, stacktrace(catch_backtrace())
.
Como nos sentimos sobre a eliminação de sublinhado C_NULL
? Eu me acostumei com isso, mas também acredito que nenhum dos outros C*
nomes tem um sublinhado.
Os outros nomes C são tipos, enquanto C_NULL
é uma constante. Acho bom como é e segue as diretrizes de nomenclatura.
e segue as diretrizes de nomenclatura.
Como assim?
Freqüentemente, as constantes são todas maiúsculas com sublinhados - C_NULL
segue isso. Como @ iamed2 disse, é um valor, não um tipo, então a convenção de nomenclatura Cfoo
não se aplica necessariamente.
Por engano, pensei https://github.com/JuliaLang/julia/blob/master/doc/src/manual/variables.md#stylistic -conventions referenciadas constantes, mas isso não acontece. Provavelmente deveria.
Eu sugiro uma interface consistente e matematicamente sólida para espaços de Hilbert gerais nos quais os vetores não são Julia Arrays. Nomes de funções como vecdot
, vecnorm
, etc. podem ser substituídos pelos conceitos gerais de inner
e norm
conforme discutido em https: // github. com / JuliaLang / julia / edições / 25565.
Como eu disse algumas vezes, essa não é uma questão abrangente para as coisas que se deseja mudar.
Acredito que os únicos itens restantes sob este guarda-chuva para 1.0 são # 25501 e # 25717.
Eu gostaria de fazer algo com (get|set)_zero_subnormals
mas talvez a melhor solução de curto prazo seja apenas desexportá-los.
Algo que provavelmente deveria ser revisado é como os números são tratados no contexto de operações de coleção como map
e collect
. Foi apontado que o primeiro retorna um escalar, mas o último retorna um array 0D.
Comentários muito úteis
Auditoria de sublinhado
A seguir está uma análise de todos os símbolos exportados do Base que contêm sublinhados, não são reprovados e não são macros de string. O principal a ser observado aqui é que esses são apenas nomes exportados; isso não inclui nomes não divulgados que pedimos às pessoas que chamem de qualificados.
Separei as coisas por categoria. Esperançosamente, isso é mais útil do que irritante.
Reflexão
Temos as seguintes macros com funções correspondentes:
@code_llvm
,code_llvm
@code_lowered
,code_lowered
@code_native
,code_native
@code_typed
,code_typed
@code_warntype
,code_warntype
Qualquer alteração aplicada às macros, se houver, deve ser aplicada de forma semelhante às funções.
module_name
->nameof
(# 25622)module_parent
->parentmodule
(# 25629, consulte # 25436 para uma tentativa anterior de renomeação)method_exists
->hasmethod
(# 25615)object_id
->objectid
(# 25615)pointer_from_objref
pointer_from_objref
talvez pudesse usar um nome mais descritivo, talvez algo comoaddress
?Aliases para interoperabilidade C
Os aliases de tipo contendo sublinhados são
C_NULL
,Cintmax_t
,Cptrdiff_t
,Csize_t
,Cssize_t
,Cuintmax_t
eCwchar_t
. Aqueles que terminam em_t
devem permanecer, pois são nomeados para serem consistentes com seus tipos C correspondentes.C_NULL
é o estranho aqui, sendo o único alias C contendo um sublinhado que não é espelhado em C (já que em C isso é apenasNULL
). Poderíamos considerar issoCNULL
.C_NULL
Contando bits
count_ones
count_zeros
trailing_ones
trailing_zeros
leading_ones
leading_zeros
Para uma discussão sobre como renomeá-los, consulte # 23531. Eu defendo a remoção dos sublinhados para estes, bem como algumas das substituições propostas nesse PR. Acho que deve ser reconsiderado.
Operações inseguras
unsafe_copyto!
unsafe_load
unsafe_pointer_to_objref
unsafe_read
unsafe_store!
unsafe_string
unsafe_trunc
unsafe_wrap
unsafe_write
Provavelmente não há problema em mantê-los como estão; a feiura do sublinhado ressalta ainda mais sua insegurança.
Indexando
broadcast_getindex
broadcast_setindex!
to_indices
Aparentemente,
broadcast_getindex
ebroadcast_setindex!
existem. Eu não entendo o que eles fazem. Talvez eles pudessem usar um nome mais descritivo?Curiosamente, a versão de índice único de
to_indices
,Base.to_index
, não é exportada.Traços
catch_backtrace
catch_stacktrace
->stacktrace(catch_backtrace())
(# 25615)Presumivelmente, esses são os
catch
equivalentes em bloco debacktrace
estacktrace
, respectivamente.Tarefas, processos e sinais
current_task
task_local_storage
disable_sigint
reenable_sigint
process_exited
process_running
Streams
redirect_stderr
redirect_stdin
redirect_stdout
nb_available
->bytesavailable
(# 25634)Seria bom ter uma função de redirecionamento
IO
->IO
mais geral na qual todos eles pudessem ser combinados, por exemplo,redirect(STDOUT, io)
, removendo assim tanto sublinhados quanto exportações.Promoção
promote_rule
promote_shape
promote_type
Veja # 23999 para uma discussão relevante sobre
promote_rule
.Impressão
print_with_color
->printstyled
(consulte # 25522)print_shortest
(consulte # 25745)escape_string
(consulte # 25620)unescape_string
escape_string
eunescape_string
são um pouco estranhos porque podem imprimir em um stream ou retornar uma string. Veja # 25620 para uma proposta para mover / renomear estes.Carregando código
include_dependency
include_string
include_dependency
. Isso é usado fora da Base? Não consigo pensar em uma situação em que você desejaria isso em vez deinclude
em qualquer cenário típico.include_string
. Esta não é apenas uma versão oficialmente sancionada deeval(parse())
?Coisas que não me incomodei em categorizar
gc_enable
->GC.enable
(# 25616)get_zero_subnormals
set_zero_subnormals
time_ns
get_zero_subnormals
eset_zero_subnormals
poderiam ser usados com nomes mais descritivos. Eles precisam ser exportados?