LINUX.ORG.RU

Почему defer из Go не принят другими ЯП?

 ,


0

6

Это же так удобно - f = fopen(path); defer({ fclose(f) })
Те мы сразу рядом написали что файл закроем. Именно рядом а не через экран строчек в каком нибудь finally или, еще хуже, в конце функции вообще.
А потом глаза ломай смотри сверяй что все что по пути было открыто - закрыто.

Знаю что можно костылить такую фичу через деструкторы в крестах и через setTimeout(..., 0)(очень плохой способ) в ЯП с event loop

★★★

В Haskell есть with* и bracket. Плюс тот же defer легко на коленке запилить и вынести в библиотеку.

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

в плюсах есть смарт поинтеры с кастомными деструкторами

harvos ()

Алсо причина в том, что этот defer очень паршиво работает в языках с эксепшонами. Коих большинство сейчас.

hateyoufeel ★★★★★ ()

Поэтому Go – это следующая реинкарнация C (после aleph). С улучшениями и дополнениями.

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

Это же так удобно

Что удобного писать это каждый раз?

no-such-file ★★★★★ ()

Потому что для этого нужен event loop, а в тех же крестах возможность выбора его реализации (или отсутствия) - это принципиальная фича

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

Это же древний паттерн. И в какой-то степени костыль, поскольку гораздо лучше использовать raii, try-with-resources, context manager, using и т.д. в зависимости от языка.

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

Алсо причина в том, что этот defer очень паршиво работает в языках с эксепшонами.

А можно развернуть?

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

Что зачем? Цикл обработки не всем нужен, и уж точно не в любом треде. Реализации отличаются эффективностью поддержкой платформ (и новых сисколлов)

annulen ★★★★★ ()

Почему defer из Go не принят другими ЯП?

Потому что в нормальных языках штуки типа `fclose` выполняются автоматически при закрытие блока

oxo ()

Знаю что можно костылить такую фичу через деструкторы в крестах

defer - это гораздо более кривой костыль, чем деструктор.

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

А потом глаза ломай смотри сверяй что все что по пути было открыто - закрыто.

Для этого есть RAII

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

Мне не понятно, зачем для реализации defer нужен eventLoop. Мне кажется, что и так банально реализуется. Я не прав?

derlafff ★★★★★ ()

в С++ RAII, вообще никакого fclose писать не нужно...

std::ifstream f(path);

fsb4000 ★★★★★ ()

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

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

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

Сразу после return, но до перехода обратно в вызывающий код. Просто еще одна функция в стек адресов возврата.

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

я тоже не могу воспроизвести. Мои извинения, почудилось.

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

Такую функцию легко написать самому, только выглядеть будет как

auto t = defer([f]{ fclose(f) })
annulen ★★★★★ ()
Ответ на: комментарий от eao197

А можно развернуть?

Я где-то даже статью видел на эту тему. Идея примерно в том же, почему в деструкторах в C++ нельзя кидать эксепшоны наружу. Не слишком понятно, выполнено ли действие до конца или нет.

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

Потому что для этого нужен event loop

Для defer не нужен event loop.

Пример того, как defer реализуется на расширениях gcc/clang.

Deleted ()

В D такое есть, более проработанное. В большинстве ЯП вообще есть какая-то более удобная автоматика.

anonymous ()

В свифте аналогичный.

Deleted ()

«недодеструктор», «протез памяти» или автоматизация управления локальным scope ?

тогда уж «принимать» всю троицу: defer, panic и recover

anonymous ()

В swift есть, не надо заливать!

menangen ★★★★★ ()

с другой стороны, всегда будет актуальным вопрос «что вернёт эта функция и почему?»:

func c() (i int) {
    defer func() { i++ }()
    return 1
}
anonymous ()

Потому что это костыль. В питоне есть ContextManager, в крестах есть ifstream, в хашкиле with.

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

Ну речь о других языках. Если а них нет зелёных потоков или чего-то подобного, то все очень просто. А если есть, то есть и event loop

vertexua ★★★★★ ()

Это не удобно хотя бы тем что это нужно писать и можно забыть.

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

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

Потому что для этого нужен event loop

Конечно же нет.

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

Ну так всю программу вообще можно в одном файле в теле main() написать, тогда можно и больше, чем десяток в цикле

nikolnik ★★★ ()

Это было реализовано ещё в первой версии языка «D». Когда ещё и GO то не было.
Вариант выполнения при выходе из функции.

void locked_foo()
{
    Mutex m = new Mutex;

    lock(m);                // lock the mutex
    scope(exit) unlock(m);  // unlock on leaving the scope

    foo();                  // do processing
}

Вариант выполнения при ошибке в функции(исключение).
Transaction transaction()
{
    Foo f = dofoo();
    scope(failure) dofoo_undo(f);

    Bar b = dobar();
    return Transaction(f, b);
}

https://dlang.org/spec/statement.html#ScopeGuardStatement

Atlant ★★★★★ ()
Последнее исправление: Atlant (всего исправлений: 2)

в С++ для этого деструкторы

next_time ★★★★★ ()

Суровые мужики файлы не закрывают. Пусть ОС сама следит если ей надо!

Alve ★★★★★ ()

Потому, что это такой костыль для языка без аффинных типов?

quantum-troll ★★★★★ ()

Ошибку не проверил, должно быть так:

f, err = fopen(path)
if err != nil {
    return fmt.Errorf("fopen: %s", err.Error())
}
defer fclose(f)


Те мы сразу рядом написали что файл закроем. Именно рядом а не через экран строчек в каком нибудь finally или, еще хуже, в конце функции вообще.

Экран строчек возникает из-за `if err != nil`, поэтому появился `defer`, в нормальных языках о такой проблеме вообще не в курсе.

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