LINUX.ORG.RU

Праздный вопрос по языкам программирования.

 


0

2

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

Есть какое-то четкое правило для такого разграничения? Чем такой код плох?

{
  print(a); // печатает 3
  a = 5;
  print(a); // печатает 5
  var a = 3;
}
Ну кроме того, что мозг ломает и потенциально баги рождает. А так - полная симметрия с функциями.

Никакого особого смысла в вопросе нет, просто воскресенье и простуда.

★★★★

Ответ на: комментарий от xmikex

а что такое декларация типов данных?

struct в Rust и Swift, например.

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

Вообще не понятно, что делает этот пример псевдокода.

«Классическая» версия будет выглядеть так:

{
  var a = 3;
  print(a); // печатает 3
  a = 5;
  print(a); // печатает 5
}
alexru ★★★★
() автор топика
{
  print(a); // печатает 3
  a = 5;
  print(a); // печатает 5
  var a = 3;
}

а отчего-бы не наоборот ? то есть сначала 5, а потом 3...или даже сначала «бла-бла-бла» (так где-ты выше/ниже по коду дано) а потом 5. Или 3 :-)

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

а отчего-бы не наоборот ?

Потому, что применяется одинаковая логика разбора. Сначала вся программа/блок просматривается и все декларации (функций, типов, переменных) «запоминаются». Потом вторым проходом генерируется код, который уже может ссылаться на еще не объявленные названия, так как они уже известны.

Почему бы такому коду:

struct A
{
  B member_of_type_b;
};

struct B
{
  int member;
};

не посчитать, что B - это int, например, ведь настоящий B объявлен позже по коду.

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

От чего же. Кое-что можно делать в haskell через рекурсивную нотацию do, которая позволяет, например, задавать обыкновенные дифференциальные уравнения в таком же произвольном порядке, как эти уравнения записываются обычно в математике. Ведь это похоже на то, о чем ты спрашиваешь?

Главное, чтобы такие определения были разрешимы. Но императивные языки это никак не потянут, потому что тут нужна ленивость и монады. Поэтому языки типа Java, C, C++, C#, Python в пролете с этой фичей

dave ★★★★★
()

В том, что его трудно понимать и компьютеру и человеку.

Логично, что если ты объявляешь переменную, то ты делаешь это до того, как начинаешь с ней работать, а не так, что ты уже написал кучу кода с какой-либо переменной, и лишь в конце решил ее объявить.

Простой пример: ты же книгу читаешь с начала, а не с конца.

И вообще, приведи пример, когда такое необходимо в коде, потому как до этого все успешно без этого обходились.

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

Насколько я слыхал, в жабаскрипте можно.

Вот, уже ближе. Такой код

alert(a);
var a=5;
alert(a);
выводит 'undefined', а потом 5. Если убрать var, то «ReferenceError: a is not defined».

Так что переменная видна, но не начальное значение.

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

В том, что его трудно понимать и компьютеру и человеку.

Компьютеру до лампочки. Наборот набор ограничивающих правил уменьшается если уже и так используется двухпроходная компиляция.

Логично, что если ты объявляешь переменную, то ты делаешь это до того, как начинаешь с ней работать, а не так, что ты уже написал кучу кода с какой-либо переменной, и лишь в конце решил ее объявить.

Логично, что когда вызываешь функцию, то ее нужно сначала объявить.

И вообще, приведи пример, когда такое необходимо в коде, потому как до этого все успешно без этого обходились.

В Си все до сих пор обходятся с объявлениями прототипов функций до использования.

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

Хотя не ясно, что делать с кодом типа

{
  print(a); // печатает ???
  a = 5;
  print(a); // печатает 5
  var a = some_function();
}

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

У нас в DSL отработает так, как ты и написал, но это полная херня по понятным причинам.

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

Если some_function объявлена, то результат функции, потом 5. Если нет – то в зависимости от языка. Но жабаскрипт, который тут уже упоминали...
P.S.: не понимаю принципиального отличия от куска в ОП.

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

P.S.: не понимаю принципиального отличия от куска в ОП.

Да, действительно, это я уже сам запутался. Наверное это лучшая иллюстрация почему это плохая идея :)

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

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

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

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

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

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

да нет, именно произвольный.

Ну как скажешь.

Где тут воля компилятора? Просто переменную можно объявить где угодно внутри блока. То же самое уже можно делать с функциями. В чем разница?

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

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

4.2. почти во всех языках типам данных нужна преждевременная декларация.

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

а я и так объявляю переменные в начале блока. потому что компиляторы и платформы бывают разные. ну и это просто удобнее, сразу видно, какие переменные есть в данном пространстве видимости.

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

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

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

Логично, что если ты объявляешь переменную, то ты делаешь это до того, как начинаешь с ней работать, а не так, что ты уже написал кучу кода с какой-либо переменной, и лишь в конце решил ее объявить.

Логично, что когда вызываешь функцию, то ее нужно сначала объявить.

C одной стороны да, с другой, будет намного удобнее в начале файла писать основную функцию, а остальные описать ниже.

И вообще, приведи пример, когда такое необходимо в коде, потому как до этого все успешно без этого обходились.

В Си все до сих пор обходятся с объявлениями прототипов функций до использования.

Тут я имею в виду объявление переменных после их использования. С функциями такого вопроса не стоит. А на счет Си - вы абсолютно правы.

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

А потом кто-то дописал строчку:

{
    print(a) // 3
    print(a) // 7 — wtf? почему не 5?
    var a = 3
    ...
    a = 7
    ...
    a = 5
}

Virtuos86 ★★★★★
()

Если кратко, то твоя идея жестко противоречит идее императивного программирования, к которому все привыкли, ибо нарушается строгая последовательность действий.

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

dave ★★★★★
()

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

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

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

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

Не противоречит, например, императивное программирование: «пойди туда, не знаю куда, принеси то, не знаю что» © не нарушает строгую последовательность действий.

Объявление переменной и связывание ее с некоторым значением после задекларированного места использования - норм, если можно разрешить эту ситуацию, а вот двойное присваивание - это уже неправильно. Либо одно, либо другое.

Аналогично условие c множественным двойным присваиванием:
«не пешком, не верхом, не голая и не одетая, не днём и не ночью, не утром и не вечером»
реализуется в виде: «явилась она на рассвете да в сети, на козле-то сидит, ногами по земле ступает» ©

P.S. :)

quickquest ★★★★★
()

Ну кроме того, что мозг ломает и потенциально баги рождает

Ну смотри, одно дело декларация по сути типа, а другое - мешанина с реальными значениями, принципиально разные на мой взгляд ситуации. Какое счастье что такого нет в ЯП которыми я пользуюсь :)

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от quickquest

Отрицание не дружит с программированием. Посмотри на пролог, к примеру.

dave ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

С мешаниной значений нет ни в одном из известных мне языков программирования. Тоже к счастью. Тут либо мешанина и строгая последовательность, либо без мешанины, но зато с запаздывающими декларациями. А так, в том виде, в каком представил ТС - ни рыба, ни мясо)

dave ★★★★★
()

А так - полная симметрия с функциями.

Нет. Полная симметрия была бы если бы ты задал две разных тушки для одной функции в одной области видимости. Плюс ты совершенно путаешь объявления и эффекты.

{
    var a;
    print(a);
    set(a,5);
    print(a);
    set(a,3);
}

Подумай, что выведет твой код, если переписать его в таком виде?

Короче, если ты хочешь симметрии, тебе нужны константы, а не переменные.

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

> В том, что его трудно понимать и компьютеру и человеку.

Компьютеру до лампочки. Наборот набор ограничивающих правил уменьшается если уже и так используется двухпроходная компиляция.

А теперь попробуй написать и сравнить, кек.

anonymous
()
module test;
  
  initial begin
    $display(x);
    x = 5;
    $display(x);
  end
  
  int x = 3;
  
endmodule

На некоторых симуляторах прокатывает:

# Aldec, Inc. Riviera-PRO version 2015.06.92.5791 built for Linux64 on July 13, 2015.
# KERNEL:           3
# KERNEL:           5
# KERNEL: Simulation has finished. There are no more test vectors to simulate.

Но в основном ошибка компиляции или первое значение 0.

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

На своём любимом Це ты это легко можешь сделать:

#include <stdio.h>

int i;

void main() {
    printf("%i\n", i);
    i = 5;
    printf("%i\n", i);
}

int i = 3;

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

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

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

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

кстати, пригляделся и я двойного присваивания у тебя не увидел)

Ну, например, так:
$на_козле.сидит = $на_козле.ногами_ступает -> getЯвилась($козёл);
$одежда.не_голая = $одежда.не_одетая -> getСеть($variantmod);
:)

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

знаешь, можно и на ассемблере написать - там точно без мутирующих присваиваний не обойтись; да даже на Сях будет сложно избежать их, но это не значит, что везде так

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

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

dave ★★★★★
()

Линукс тут при чём?

anonymous
()

Телефоном дилера поделишься?

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

на многоядерных процах всё это разруливается через фенсы и всяческие локи памяти, если приспичит. это довольно редко, но иногда нужно.

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

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

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

я не понимаю, зачем это нужно

А *ничего* и не нужно. В принципе.

недетерминированное поведение софта - это, по сути, баг

Lo! Both logic and concurrent programming have just been busted by LOR experts.

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

Конечно понял. BS, как обычно.

Недетерминированные подходы используется почему-то. От методов Монте-Карло (численное моделирование), до — наиболее яркий пример-- стохастических солверов для Curry (логическое программирование).

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