LINUX.ORG.RU

Не баг, а фича

 


0

2

Какие вещи в программирования изначально появились как эдакая недоработка, но потом приобрела `статус фичи`?

Вот как мне кажется (на достоверность не претендую) например лисп - ребятам просто лень было доделывать. Динамическая типизация - разумеется товарищи типа Гвидо и Мацумото знают о преимуществах статической - но её просто сложно сделать, `и так пойдёт`.

Что ещё есть?

Перемещено JB из talks

★★★★★

Последнее исправление: Debasher (всего исправлений: 1)

Нет такого. Стандарты нормальных языков разрабатывают умные дядьки. А эти языки как только появились и, соответственно, ещё не имели стандартов, разрабатывались этими же умными дядьками, только ещё тогда молодыми.
Но я это про нормальные языки. Про ПХП и прочее не знаю как там эти языки живут и чем болеют.

Stahl ★★☆
()
Ответ на: комментарий от next_time

JavaScript

Безусловно, он возглавляет список :)

Debasher ★★★★★
() автор топика
Ответ на: комментарий от deterok

Ты что-то где-то явно не дочитал.

Скорее всего

Про какие конкретно фичи ты говоришь?

Если бы знал про какие - не спрашивал бы )

Debasher ★★★★★
() автор топика

В лиспе с типизацией все ок, Маккарти хотел синтаксис к нему прикрутить, но в итоге решил, что «и так сойдет».

staseg ★★★★★
()

фунарг проблема из-за варианта реализации Кнайтом.

ну и не стек вложенностей а цепь записей активации что легче преобразовать в дерево таковых - ну а затем отцепить и получить полноценные замыкания.

qulinxao ★★☆
()

Баг в интерпретаторе питона, из-за которого количество пробелов влияет на выполнение кода, почему-то зовут фичей.

hateyoufeel ★★★★★
()
Ответ на: комментарий от hateyoufeel

А чем пробел хуже других знаков? (При условии, что табы нельзя пихать в перемешку с пробелами, а язык нормально парсит все пробелоподобные знаки типа  )

zinfandel ★★
()

Указатели в си же. Хотели сделать строки, получилось вот как-то так.

unt1tled ★★★★
()

Динамическая типизация - разумеется товарищи типа Гвидо и Мацумото знают о преимуществах статической - но её просто сложно сделать, `и так пойдёт`.

Товарищи типа Гвидо и Мацумото знают так же и о недостатках статической типизации.

Ещё синтаксис для методов расширения в D. Для реализации вызова у объектов методов компилятор просто передавал значение перед точкой первым аргументом, т.е. «func(arg1, arg2, arg3)» и «arg1.func(arg2, arg3)» было абсолютно эквивалентно. Бага прижилась...

Gentooshnik ★★★★★
()
Ответ на: комментарий от Gentooshnik

Так а че в лиспе разве нету статической типизации?

Я думаю, он про синтаксис вызова функции (func arg1 arg2 arg3) вместо func[arg1; arg2; arg3].

Нет.

Debasher ★★★★★
() автор топика
Ответ на: комментарий от Int0l

Так а че в лиспе разве нету статической типизации?

Это два разных, несвязанных примера. Про статическую типизацию в лиспе можно поговорить, но сначала давай набухаемся.

Debasher ★★★★★
() автор топика
Ответ на: комментарий от Int0l

Может вы имеете ввиду «систему типов» типа как в Haskell?

Не очень знаю как в хаскелле, я сейчас изучаю ocaml и мне очень нравится когда не теряя выразительной способности лиспа можно внедрить такой способ контроля кода.

Debasher ★★★★★
() автор топика
Последнее исправление: Debasher (всего исправлений: 1)

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. [..] My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

Tony Hoare

Понадобилось 50 лет, чтобы с выходом Rust 1.0 наконец-то профиксить эту багу.

nonimous
()

Точка с запятой в конце statement. Указание типа слева от переменной. Значение null.

dizza ★★★★★
()
Ответ на: комментарий от Gentooshnik

Товарищи типа Гвидо и Мацумото знают так же и о недостатках статической типизации.

О каких, например?

hateyoufeel ★★★★★
()

Гвидо и Мацумото знают о преимуществах статической - но её просто сложно сделать, `и так пойдёт`.

удивления и непонимания возникают у товарища когда делают что-то не так как он принял считать правильным, осторожнее с ним, возможно он закостенел.

pseudo-cat ★★★
()
Ответ на: комментарий от Debasher

я сейчас изучаю ocaml и мне очень нравится когда не теряя выразительной способности лиспа можно внедрить такой способ контроля кода

Теряя. Тривиальные вещи типа (if (= x 0) :error (/ y x)) превращаются во что-то ужасное.

monk ★★★★★
()
Ответ на: комментарий от pseudo-cat

удивления и непонимания возникают у товарища когда делают что-то не так как он принял считать правильным, осторожнее с ним, возможно он закостенел.

удивления и непонимания возникают у товарища когда ему надо поддерживать систему на динамическом языке когда весь нужный контекст в голову не влезает

Debasher ★★★★★
() автор топика
Ответ на: комментарий от Debasher

if x = 0 then None else Some(y / x)

Не-не-не. Нужен не нулл (None), а Error.

Вот более подробный пример:

(defun connect (host)
  (cond
    ((bad-hostname? host) :bad-hostname)
    ((can-connect? host) (really-connect host))
    (else :cannot-connect)))

Или вот такие типы: http://www.erlang.org/doc/man/gen_tcp.html#recv-2

В языках со статической типизацией приходится извращаться: если значение меньше нуля, значит это код ошибки (Си) или после операции проверяй флаг ошибки (Си++).

monk ★★★★★
()

товарищи типа Гвидо и Мацумото знают о преимуществах статической - но её просто сложно сделать, `и так пойдёт`.

Толсто. Динамическую реализовать должно быть сложнее, чем статическую. И при динамической нет необходимости думать, какой тип данных использовать. Не верится, что это могло быть багом.

Klymedy ★★★★★
()
Ответ на: комментарий от Debasher

когда ему надо поддерживать систему на динамическом языке когда весь нужный контекст в голову не влезает

А чем это отличается от статической типизации? Только тем, что типы проверяются при запуске. В модели они ведь по-прежнему есть. Но нет жёстких ограничений системы типов, заданных языком.

Вот http://www.erlang.org/doc/man/gen_tcp.html#recv-2 . Я не могу (точнее могу, но слишком много камасутры) сделать в *ML/Haskell типы Length = integer() >= 0, Packet = string() | binary() | HttpPacket, Reason = closed | inet:posix().

monk ★★★★★
()
Ответ на: комментарий от monk

Не-не-не. Нужен не нулл (None), а Error.

Это не нулл. Это `вот такой тип`, как по ссылке.

В языках со статической типизацией приходится извращаться: если значение меньше нуля, значит это код ошибки (Си) или после операции проверяй флаг ошибки (Си++).

Я про языки с _нормальной_ статической типизацией, конкретно пример на ocaml. В си типизации считай нет.

Вот более подробный пример:

type connect_status = Success | BadHostname of string | CannotConnect of string;;

    
let connect host = if (bad_hostname host) then BadHostname("плохой хост")
                   else if (can_connect host) then really_connect host
                   else CannotConnect("неполучилося");;

(код примерный, не тестил)

Debasher ★★★★★
() автор топика
Последнее исправление: Debasher (всего исправлений: 1)
Ответ на: комментарий от monk

А чем это отличается от статической типизации?

Тем, что не окажется что какую-то из 100500 веток кода после изменений забыл протестировать и никто не заметит и вылезет когда-нибудь.

Debasher ★★★★★
() автор топика
Ответ на: комментарий от Klymedy

Динамическую реализовать должно быть сложнее, чем статическую.

Я не реализовывал ни одну из них, но как мне представляется с динамической намного проще - если операция позволяется - делаем, инасче ошибку кидаем.

Со статической, видимо (могу ересь нести) нужно реализовывать эдакое отражение ast дерева, только состоящее из типов, и проверить его корректность. Причём, мы же не хотим терять выразительную способность, поэтому типы должны быть умными, как в этих ваших хаскелях и ml'ях.

Debasher ★★★★★
() автор топика
Ответ на: комментарий от Debasher

Тем, что не окажется что какую-то из 100500 веток кода после изменений забыл протестировать

Для этого придуманы юнит-тесты. И статическая типизация не позволяет от них отказаться. От того, что у тебя будет значение правильного типа, но неверное — легче не будет.

monk ★★★★★
()
Ответ на: комментарий от monk

В языках со статической типизацией приходится извращаться

Не обобщай С на «языки со статической типизацией»: http://is.gd/v9WUrQ . При таком варианте возможные ошибки становятся частью сигнатуры метода, и вызывающий код вынужден так или иначе обработать возможность ошибок. В то время как твоем лишпокоде ты можешь сделать

(transfer-data (connect "example.com"))
, и словить ошибку только в рантайме.

nonimous
()
Ответ на: комментарий от Debasher

type connect_status = Success | BadHostname of string | CannotConnect of string;;

Можно и просто

type connect_status = Success of socket | BadHostname | CannotConnect

А потом другая функция должна вернуть

(defun calc (x)
  (cond
    ((> x MAX) :overflow)
    ((= x 0) :zero)
    (else (real-calc x))))

Пишем для неё тип:

type calc_status = Success of number | Overflow | Zero

Упс. Success использовать нельзя. Он уже есть в другом типе. Потом в третьей функции надо различать Success | Zero | Underflow... Приходится делать уродливые Success2, Zero2, ... это я и называю «камасутрой»

monk ★★★★★
()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от nonimous

и вызывающий код вынужден так или иначе обработать возможность ошибок ... В то время как твоем лишпокоде ты можешь ... словить ошибку только в рантайме.

Я не понял: по твоей ссылке

println!("{:?}", connect("bad.com"));

словит ошибку при компиляции???

monk ★★★★★
()
Ответ на: комментарий от monk

Я не могу (точнее могу, но слишком много камасутры) сделать в *ML/Haskell типы Length = integer() >= 0, Packet = string() | binary() | HttpPacket, Reason = closed | inet:posix().

Ты не поверишь:

type Length = Word
data Packet = StringPacket String | BinPacket Binary | HttpPacket
data Reason = ReasonClosed | ReasonPosix PosixReasonId

nonimous
()
Ответ на: комментарий от nonimous

Ты не поверишь

И во что прерватится

{ok,Sock} = gen_tcp:connect("localhost",PortNo,[list]),
{ok,Packet} = gen_tcp:recv(Sock, 0)
io:write(Packet) // Packet -- строка, так как тип соединения [list]
?

monk ★★★★★
()
Ответ на: комментарий от monk

Как Erlang обработает ошибки в твоем коде? Если паникой, то в

fun = do
    Right(sock) <- connect("localhost", port_no)
    Right(packet) <- recv(sock, 0)
    write(packet)
Если засунуть IO в EitherT, то будет еще проще и без паники:
fun = do
    sock <- connect("localhost", port_no)
    packet <- recv(sock, 0)
    write(packet)

nonimous
()
Ответ на: комментарий от nonimous

использование результата без обработки ошибок

И заставляет обрабатывать ошибки даже там, где их уже быть не может. Например, для calc мне нельзя написать calc(3) + calc(4), а надо писать

match calc(3) {
            Ok(c) => {
                c;
            },
            Err(e) => println!("{}: error {:?}", h, e)
        } +
match calc(4) {
            Ok(c) => {
                c;
            },
            Err(e) => println!("{}: error {:?}", h, e)
        }

monk ★★★★★
()
Ответ на: комментарий от monk

Приходится на эрланге писать? Понимаю, соболезную. В нормальнух языках будут, например, ф-ции write_list, write_bytestring и т.д., отображающие аргумент в сишную строку. А указывать тип данных при создании сокета — не очень понятный костыль, ибо tcp про ваши lists и binaries ничего не знает.

fmdw
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.