Что такое идиоматика?

19

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

i = i + 1;

В C ++ эта идиома упрощается оператором:

++i;

Однако, когда кто-то использует термин «идиоматический», я не уверен, как это понимать. Что делает кусок кода "идиоматическим"?

void.pointer
источник
На сайте english.stackexchange.com он принадлежит столько же, сколько и здесь.
S.Lott
@ perl.j: проницательный. Вы действительно разъяснили, почему определение «идиоматический» не принадлежит на сайте english.stackexchange.com. Очень полезно.
S.Lott

Ответы:

24

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

Например, в C ++ использование идиомы RAII приводит к написанию кода для C ++, который управляет идиоматическими ресурсами.

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

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

Klaim
источник
Отличное описание. Таким образом, в C #, если я создаю метод расширения, вызываемый TryAdd()для общего Dictionaryкласса, чтобы сначала проверить, !Contains()а затем вызвать Add(), это было бы идиоматично? Я использую особенность методов расширения C #.
void.pointer
1
Я не уверен точно, так как самый опытный программист C ++ сказал бы вам писать бесплатные функции для расширения классов вместо добавления членов, где это возможно. Это не то же самое, что методы расширения C #, но это довольно близко и доступно для любого языка, который допускает бесплатные функции. Что я уверен, так это то, что написание «set / getters» в C # с использованием свойств является идиоматическим.
Klaim
Но это не C ++, поэтому использование «пути C ++» может быть недостаточно «идиоматическим». Использование метода расширения здесь разумно и очень похоже на C #. В любом случае это был пример, но методы расширения очень идиоматичны для C #.
void.pointer
Да, именно поэтому я сказал «я не уверен», это кажется идиоматическим, но это настолько близко к другим основным функциям других языков, что я не уверен (потому что я не C # dev). У меня есть еще один пример: зацикливание выполняется путем рекурсии во всех функциональных языках. Вы можете сделать это на других языках, но это явно идиоматично для функциональных языков. Не уверен, что это поможет.
Klaim
1
Конечно, Python делает еще один шаг вперед, имея идиоматический способ обращения к идиоматическому коду, то есть pythonic. * 8 ')
Марк Бут
12

Нормальное определение

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

Определение программирования

Используя, содержащий или обозначая выражения , которые являются естественными для [Insert Language] программатора

ChaosPandion
источник
1
Если бы я думал, что определения "google" для этого термина были полезны, я бы не стал размещать здесь. Я хотел лучшее описание (как учебник) с примерами.
void.pointer
3
@ Роберт - Думаю, я не понимаю, почему ты не понимаешь.
ChaosPandion
2
Сначала я прочитал ваш ответ, это было не совсем понятно. Прочитав ответ, который теперь помечен как мой ответ, стало очень ясно, что означает «идиоматический», и теперь я понимаю это. Теперь, когда я прочитал ваш ответ, это имеет смысл. Тем не менее, вы не проводили меня через примеры и разные сценарии, поэтому я думаю, что ваш ответ не был таким полезным. Вы дали ответ «Вебстер», который технически верен, но не помогает мне понять. Я ценю вашу помощь, хотя.
void.pointer
7

Идиоматика в контексте программирования обычно может быть определена как «наиболее естественный способ выразить что-либо на языке»

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

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

Таким образом, в основном идиоматический чаще всего относится к наиболее распространенному способу написания чего-либо на языке, часто в том числе «сленг» (идиомы). Если фрагмент кода не является идиоматическим, он может быть отлично читаемым, кратким, чистым и правильным, но он может выглядеть / выглядеть неловко на используемом языке. Это предпочтение вкуса в отношении того, будет ли переписывание такого фрагмента кода идиоматически действительно полезным и должно оцениваться в каждом отдельном случае.

Например, идиоматический английский может зависеть от региона. Использование этого слова bum, вероятно, требуется для идиоматического английского в Великобритании, тогда buttкак больше подходит для английского в США. (Я не знаю много британского английского, к сожалению: /)

Earlz
источник
Спасибо (с одобрением), я думаю, что ваше определение попало прямо на месте для меня!
Ашаман Кингпен
3

Лучший пример, который я могу придумать, идиотизм, для чего-то идиоматического, - это Ruby.

На множестве языков вы можете выполнять итерации с помощью:

for( start; end; increment){
    code;
}

Или что-то очень похожее. Многие языки также имеют foreach(x in SetOfXes)конструкцию. Но итерация для Ruby включает в себя такие вещи, как:

collection.each do |current|
  current.do_stuff
end

и даже

10.times do |x|
  puts x
end

Я считаю их идиоматическими, потому что они представляют собой способ сделать что-то менее распространенное, и это представляет собой нечто в основе философии своей области. У Ruby есть философия взаимодействия с объектами, которая, хотя и не уникальна, не является вездесущей.

На семантической ноте, когда я слышу слово «идиоматический», мой мозг автоматически завершает мысль как «идиоматический для ...» - я просто рефлексивно разбираю его как относящийся к определенному предмету.

asfallows
источник
Чем collection.each do |current|отличается от foreach(current in collection)? Оба являются циклами, которые устанавливаются currentдля каждого элемента collection.
MSalters
2

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

Идиомы - лучший способ использовать язык, как определено опытными пользователями. Настоящая идиома C ++ - это функциональные объекты. Другой идиомой был бы RAII. В языке нет ничего, что говорило бы вам о том, что вы должны освободить ресурсы в деструкторе. Но это идиоматично. Другой пример - шаблоны - идиоматично использовать шаблоны для всего, что вы можете, но ничто не мешает вам чрезмерно использовать наследование.

DeadMG
источник
Википедия использовала инкремент в качестве примера, поэтому я упомянул об этом в своем вопросе. Почему идиомы должны быть сложными? Это не похоже на определение, основанное на других ответах.
void.pointer
4
@ Роберт Дейли: Как приращение может быть идиомой? Это часть языка . Идиомы сделаны пользователями языка, они меняются со временем. Инкремент - это не идиома, это базовая функциональность языка. Используя эту логику, я мог бы сказать, что любая другая базовая языковая функция является идиомой, и поэтому каждая программа является идиоматической, а это не так.
DeadMG
2

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

Это может быть проще объяснить, говоря о том, что не является идиоматическим. В C ++ довольно идиоматично писать:

Foo* p = SomeThingThatReturnsAFooPointer(arg, param, x, y);
if(p)
{
 // whatever
}

Еще более идиоматично писать:

Foo* p; 
if(p = SomeThingThatReturnsAFooPointer(arg, param, x, y))
{
 // whatever
}

Этот код делает то же самое - некоторые новички в C ++ могут прочитать его как тестирование, чтобы увидеть, равно ли p тому, что возвращает функция, но это не то, что она делает.

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

Foo* p = SomeThingThatReturnsAFooPointer(arg, param, x, y);
if(p !=NULL)
{
 // whatever
}

Вы также увидите, что эти вещи выбиты как не-идиоматические:

if (x>0)
  return true;
else
 return false;

Потому что идиоматический подход

return (x>0);

Неидиоматические способы не являются неправильными, но они обычно занимают больше времени, чтобы печатать, и они всегда занимают больше времени, чтобы читать, для тех, кто знает идиомы. Если я назову вас «мальчиком, который плакал волком», и вы узнаете историю, это будет быстрее, чем если бы я объяснил, как ложные тревоги заставляют людей игнорировать вас. Проблема, конечно, в том, что если вы не знаете историю и не знаете, как волки связаны с тем, о чем мы говорим. Точно так же это может быть проблемой, если вы никогда не видели return x<y;раньше и действительно не знаете, что он делает.

Кейт Грегори
источник
1
Идиоматический подход, безусловно, заключался бы в объявлении указателя в условии if, чтобы к нему никогда нельзя было получить доступ, если он не равен NULL. if(Foo* p = SomeThingThatReturnsAFooPointer(arg, param, x, y))
DeadMG
мм, наверное. Или на тысячу строк раньше, потому что он используется в этом блоке. Или в заголовочном файле, потому что это переменная-член. Я только объявил об этом, чтобы читатели знали, что это Foo *, вы правы, что в реальной жизни это не будет объявлено там.
Кейт Грегори
1

Когда есть несколько способов выразить что-либо, наиболее распространенный или общепринятый способ. Например, используя структурированный оператор в C вместо точного эквивалента, используя операторы goto.

hotpaw2
источник