Co to jest idiomatyczny kod?

1

Jak w temacie. Myślę że pierwszy raz spotkałem się ze stwierdzeniem "Idiomatyczny kod" czytając książkę o Pythonie. Potem dowiedziałem się że w Pythonie mają świra że wszystko może być zrobine w tylko jeden słyszny sposób. A jeśli się tego nie da zrobić na poziomie języka to mówią że sposób A jest dobry (idiomatyczny) a sposób B jest zły (nieidiomatyczny). Czy moje zrozumienie idiomatyczności jest poprawne? Czy w Pythonie dalej są tak zakręceni?

A co jeśli język pozwala coś zrobić na dwa sposoby (lub o zgrozo więcej), np jak C# w którym można użyć LINQu (czyli specjalnej składni do składania monad), albo można te monady flatmapować ręcznie za pomocą metody SelectMany. Czy oba sposoby mogą być idiomatyczne? Czy tylko jeden jest słuszny?

4

[@stivens]: Nieidiomatyczny kod to np. Java w skladni Kotlina albo Scali


[@KamilAdam]: a jakieś przykłady?


class Foo {
  private lateinit var bar: Bar
  private lateinit var buzz: Buzz

  constructor(bar: Bar, buzz: Buzz) {
    this.bar = bar
    this.buzz = buzz
  }

  constructor(bar: Bar) {
    this.bar = bar
    this.buzz = DefaultBuzz
  }
  constructor(buzz: Buzz) {
    this.bar = DefaultBar
    this.buzz = buzz
  }

  constructor() {
    this.bar = DefaultBar
    this.buzz = DefaultBuzz
  }

  fun setBar(bar: Bar) {
    this.bar = bar
  }

  fun getBar(): Bar {
    return bar
  }

  fun setBuzz(buzz: Buzz) {
    this.buzz = buzz
  }

  fun getBuzz(): Buzz {
    return buzz
  }
}
class Foo(val bar: Bar = DefaultBar, val buzz: Buzz = DefaultBuzz)
0

@stivens: dzięki, teraz rodzi mi się w głowie kolejne pytanie - czy zawsze krótszy kod jest bardziej idiomatyczny?

6

Spotkałem się z tym określeniem kilka razy. Za każdym razem pochodziło to od osoby, która hobbystycznie dorabiała sobie na boku pouczając profesjonalistów jak mają programować, bądź od świeżaka świeżo po lekturze książki autorstwa takiego hobbysty.

4

Nigdy nie spotkałem się ze ścisłą definicją czym jest idiomatyczny kod, więc zawsze rozumiałem to określenie tak jak wynika z nazwy, czyli wybieranie spośród wielu sposobów na zapisanie danego programu takiego, który jest utarty i często spotykany. Ewentualnie, jeśli nie ma utartego schamatu, trzymanie się tych samych form na przestrzeni danego programu. Np. w perlu jest wiele sposobów na przechwycenie parametrów funkcji, ale najbardziej kanoniczny jest taki:

sub fun {
    my ($a, $b, $c) = @_;

choć ktoś mógłby zapisać:

sub fun {
     my $a = shift @_;
     my $b = shift @_;
     my $c = shift @_;

A już na pewno nie jest idiomatyczne odnoszenie się za pomocą $_[0], $_[1], $_[2].

Pierwsza jednak jest czytelniejsza, uchodząca za powszechniejszą. Poza tym skojarzenie jest takie, że idiom w językach naturalnych oznacza coś więcej niż same słowa, które go tworzą, a zatem kod idiomatyczny również powinien być zwięzły. Tak samo jeśli piszę funkcję przypominającą sort, jednak działającą na iteratorach:

my $x = iterator_sort { $a > $b } $y;

idiomatycznym jest użycie nazw funkcji $a i $b, tak jak robi to standardowa funkcja sort choć teoretycznie nazwa mogłyby być dowolne. Idąc dalej tym tropem, im bardziej projektując API, staram się wykorzystywać powszechne schematy tym bardziej idiomatyczny jest kod. Jednak tak naprawdę nie wiadomo co podmiot liryczny miał na myśli, bo nigdy z konkretną definicją się nie spotkałem.

4

Myśle, że chodzi o pewne utarte sposoby pisania, np. inicjalizacja zmiennej w JS do jakiejś innej zmiennej, chyba, że jest pusta, to przypisz wartość domyślną. Zwykle się robi to tak idiomatycznie:

const foo = bar || "some default value";

ale można to zrobić w sposób verbose:

let foo = "some default value";
if (bar) {
	foo = bar;
}

albo też tak

const foo = bar? bar : "some default value";
1
KamilAdam napisał(a):

Jak w temacie. Myślę że pierwszy raz spotkałem się ze stwierdzeniem "Idiomatyczny kod" czytając książkę o Pythonie. Potem dowiedziałem się że w Pythonie mają świra że wszystko może być zrobine w tylko jeden słyszny sposób. A jeśli się tego nie da zrobić na poziomie języka to mówią że sposób A jest dobry (idiomatyczny) a sposób B jest zły (nieidiomatyczny). Czy moje zrozumienie idiomatyczności jest poprawne? Czy w Pythonie dalej są tak zakręceni?

Z Pythonem jest jak z sexem. Wszystko pięknie dopóki trzymasz się z daleka od śliniących się zboczeńców.

Kod idiomatyczny to jest niebezpieczna patologia polegająca na stosowaniu zapisu w sposób niestandardowy, właściwy tylko dla danego języka, pewnych powszechnych operacji skutkujący spadkiem jego czytelności dla uzyskania "korzyści" w postaci oszczędności miejsca. Nie mylić z konwencją. Doskonały przykład w dodatku błędogenny ostatnio skomentowałeś na moim mikroblogu. ;)

5
PanamaJoe napisał(a):

Kod idiomatyczny to jest niebezpieczna patologia polegająca na stosowaniu zapisu w sposób niestandardowy, właściwy tylko dla danego języka, pewnych powszechnych operacji skutkujący spadkiem jego czytelności dla uzyskania "korzyści" w postaci oszczędności miejsca.

Przecież jest zupełnie na odwrót. Pisanie idiomatyczne to pisanie w sposób standardowy dla danego języka, w sposób przyjęty przez społeczność, oczywisty dla ludzi siedzących w danej technologii (przykład z const foo = bar || "some default value"; pasuje idealnie). Nawet niekoniecznie się to wiąże ze skróceniem kodu, tak jak idiomy w języku naturalnym nie służą do skracania.

4

Zależy jak zdefiniować tą idiomatyczność, ale generalnie zgadzam się z tym co napisał @Saalin powyżej. Jak dla mnie to większość doświadczonych programistów większość czasu pisze kod w sposób idiomatyczny, bo się nawzajem naśladują, kopiują dobre praktyki (średniawo to idzie, ale jednak) i styl programistów danego języka staje się zbieżny. Problem jest dopiero wtedy, gdy tą idiomatyczność traktuje się w sposób fundamentalistyczny. Trzeba znaleźć pewien kompromis.

0

@KamilAdam: jest na odwrót i być może zbyt starą książkę wziąłeś do ręki.

Chodzi o to, że w językach c, java i np. haskell inaczej pisze się programy - i co ciekawe jak już masz swój styl z innych języków to pythonie w pewnym sensie możesz próbować bazować na tym co już umiesz, odtwarzać tak jak do tej pory to robiłeś pomijając całą otoczkę jaka python wnosi.

Natomiast pojęcie idiomatyczny jest trochę na wyrost, chodzi między innymi o to, że python jest językiem, który po prostu warto poznać. Za tymi "idiomami" o których mowa zwykle chodzi o:

  • coś związanego z wydajnoscią
  • coś związanego z elastycznością
  • prostszą alternatywą pozwalającą zrezygnować z klas

i tyle. Nie znasz? Nie chcesz znać? Luzik, pisz klasy albo najlepiej monady :-P

1

Kod idiomatyczny to inaczej specyficzny, uznany przez społeczność danego języka sposób na rozwiązanie danego problemu.
Nie-stosowanie się do tych sposobów jest specyficzne dla ludzi którzy:

  • są początkujący
  • są zaawansowani, ale nie mieli jeszcze czasu na wnikanie w szczegóły danego języka

Tak jak napisał wyżej @fgh - może chodzić o wydajność lub zwięzłość.

Pisanie tak jak napisał @PanamaJoe - w ten sam sposób w każdym języku wg mnie pozbawia sensu stosowanie wielu języków.

Jeśli chodzi o podejście "pythonic" to bez niego Python nie ma często sensu, ponieważ sam w sobie nie jest demonem prędkości i nie stosowanie się do pewnych zaleceń może skutkować albo tragiczną wydajnością, albo blokowaniem ew. profitów (wynikających z jakiegoś tam ewentualnego toola) albo może być po prostu nieczytelne dla innych programistów Pythona.

Przykładowe całe OOP w Pythonie jest znacząco różne od Javy z niektórymi zasadami wprost sprzecznymi z tymi z Javy.
Patrz np. reguła #42 w Effective Python ("Prefer Public Attributes Over Private Ones").
Inny przykład to metaklasy dzięki którym można obsługiwać atrybuty w ten sam sposób w niepowiązanych ze sobą klasach.

Polecam książki:

I strony:

Jeden z pierwszych idiomów z jakimi się spotkałem w Pythonie to kopiowanie list:

list_a = [1,2,3,4,5]
list_a_copy = list_a[:]

Można by też napisać tak:

list_a = [1,2,3,4,5]
list_a_copy = list_a.copy()

Ale wersja idiomatyczna jest bardziej popularna i będziesz miał zgryz jeśli jej nie poznasz, ew. będziesz psuł kod innym jeśli nie będziesz jej stosował.

W C++ jak wspomniałem w innym wątku jest tych idiomów też sporo i miałbyś duży problem gdybyś sie do nich nie stosował (wynajdowanie koła na nowo).
https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms

0

Każ grupie deweloperów napisać jakiś kod w danym języku w taki sposób, żeby każdy napisał go sam po swojemu. Ten sposób, który występuje najczęściej jest idiomatyczny. Oczywiście samo określenie jest bardzo z d**y, bo idiomatyczność bardzo zależy od otoczenia, czy nawet mody. Spróbuj pokazać java deweloperowi z 2021 roku kod z 1995 (albo na odwrót): w obu przypadkach będzie szok i oskarżenia o brak idiomatyczności czy to spowodowane zbytnym cudowaniem (np. użycie VAVRa przez dewelopera z 2021) czy zbytne przeinżynierowanie (np. Java RMI dla developera z poprzedniego tysiąclecia)

0
vpiotr napisał(a):

Pisanie tak jak napisał @PanamaJoe - w ten sam sposób w każdym języku wg mnie pozbawia sensu stosowanie wielu języków.

Czegoś takiego nie napisałem. Stosowanie różnych języków ma sens jeżeli mają różne paradygmaty. Jeżeli mają różne formy zapisu w tym jeden udziwnioną, to sorry, ale PO CO?

Jeden z pierwszych idiomów z jakimi się spotkałem w Pythonie to kopiowanie list:

list_a = [1,2,3,4,5]
list_a_copy = list_a[:]

Można by też napisać tak:

list_a = [1,2,3,4,5]
list_a_copy = list_a.copy()

Dzięki za poparcie. Utrata przejrzystości jest ewidentna.

0
vpiotr napisał(a):

W C++ jak wspomniałem w innym wątku jest tych idiomów też sporo i miałbyś duży problem gdybyś sie do nich nie stosował (wynajdowanie koła na nowo).
https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms

hm, to czym się różnią w takim razie idiomy od wzorców projektowych lub dobrych praktyk?

3
KamilAdam napisał(a):
vpiotr napisał(a):

W C++ jak wspomniałem w innym wątku jest tych idiomów też sporo i miałbyś duży problem gdybyś sie do nich nie stosował (wynajdowanie koła na nowo).
https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms

hm, to czym się różnią w takim razie idiomy od wzorców projektowych lub dobrych praktyk?

Wg mnie...

Wzorce projektowe są bardzo ogólne i ponad językami.
Chodzi bardziej o cechy danego języka.
Np. taki kod nieświadomie tworzyłem na samym początku moich kontaktów z PHP, a wcześniej umiałem już Pascala i podstawy c++.
Sprowadzało się to do tego, że choć sam program działał poprawnie a same algorytmy były także z logicznego punku widzenia właściwe to niestety w PHP należało pisać zupełnie inaczej niż w C++.
Napisanie w C++ własnej funkcji wyszukującej indeksu elementu w tablicy ( przeszukiwanie tablicy ) czy sortowania nie jest niczym nadzwyczajnym i jeśli nie mamy akurat dostępu do jakiejś gotowej biblioteki to implementacja takiego rozwiązania na zwykłych pętlach będzie jak najbardziej poprawna.
Zrobienie czegoś takiego w PHP ... No cóż. Zadziałać zadziała ale należałoby zastosować wbudowane funkcje gdyż te są dziesiątki razy szybsze od ręcznie zaimplementowanego algorytmu.

Czyli to taki kod co jest niby poprawny, czytelny, być może spełnia wszystkie zasady SOLID itp.. itd.. do tego działa - ale jednak nie tak się to robi bo PHP ma do tego swoje specyficzne rozwiązania.

Tak przynajmniej bym to określił...

1

Idiom - wyrażenie, którego nie da się przetłumaczyć na inny język zachowując ten sam sens. Przetłumacz na polski deadline albo na angielski jakoś to będzie

~Wszystkie języki programowania mają instrukcje warunkowe, pętle, zmienne, operatory. W teorii wystarczy to do napisania każdego programu. Jednak niektóre języki mają w sobie dodatkowe rozwiązania, gdzieś wyżej miałeś przykład z Kotlinem. Idiomatyczny kod, to po prostu kod korzystający ze specyficznych cech języka, którego używasz. Czasami ma to jakąś rzeczywistą wartość, czasami jedynie pozwala jedynie pałować się wzajemnie fanbojom jakiegoś rozwiązania i reszcie świata. Dla przykładu w Pythonie, czy tam w NumPy masz całkiem sprawną składnię do zabaw tablicami, a w JS miły sposób wrzucania literałów obiektów. Nie musisz z tego korzystać, bo pętla, if, zmienna i pójdzie, tak jak to idzie w każdym języku, ale wiedząc i używając takich narzędzi napiszesz trochę szybciej i będzie trochę czytelniej.

0
piotrpo napisał(a):

Idiomatyczny kod, to po prostu kod korzystający ze specyficznych cech języka, którego używasz. Czasami ma to jakąś rzeczywistą wartość, czasami jedynie pozwala jedynie pałować się wzajemnie fanbojom jakiegoś rozwiązania i reszcie świata.

Pamiętam z "młodości" wojny Pascal vs C++ i argument **przeciążalności operatorów ** :-)

3

Wzorce projektowe da się wyrazić w różnych językach a idiomów nie. Przykład z Pythonem: domknięcia.

def funkcja():
	zmienna = 10

	def funkcja2():
		print(zmienna)
	
	def funkcja3():
		zmienna = 13
		print(zmienna)
	
	def funkcja4(zmienna = 55):
		print(zmienna)
	
	funkcja2()
	funkcja3()
	funkcja4()

Tego nie da się wyrazić np. w C, bo C nie obsługuje domknięć. Tak samo jak w Ruby można wywołać metodę literału np.

65.chr

Rzeczy typu sortowanie, wzorce projektowe itp. da się wyrazić w wielu językach, choć zapis może być czasem dziwaczny. Samo w sobie pisanie idiomami nie jest złe. Gorzej, jeśli przez to kod jest nieczytelny. Czasem mam wrażenie, że im bardziej ktoś pisze nieczytelny i idiomatyczny kod, tym bardziej rośnie ego tej osoby. Wtedy to bardziej idiotyczny kod ;)

1

Wzorce projektowe da się wyrazić w różnych językach

Niby tak, ale nie zawsze ma to sens. Przykład, po co w Kotlinie stosować wzorzec Builder, skoro są parametry domyślne i nazwane? Albo, po co stosować w tym języku proxy, skoro jest delegowanie implementacji.

Generalnie spora część wzorców powstała, żeby rozwiązywać problemy stworzone przez sam język.

1

Builder w Kotlinie ma sens. Ale do budowania faktycznie zlozonych "obiektow" a nie do wykonstruowania klasy z 5 parametrami.

Vide https://kotlinlang.org/docs/type-safe-builders.html

1
piotrpo napisał(a):

Wzorce projektowe da się wyrazić w różnych językach

Generalnie spora część wzorców powstała, żeby rozwiązywać problemy stworzone przez sam język.

Wydaje mi się, że wzorce projektowe są jednak warstwą bardziej abstrakcyjną. Faktycznie są one fizycznie zaimplementowane w języku ale sama nich idea jest jednak narzędziem bliższym logice biznesowej dzięki czemu łatwiej dyskutować o konkretnych rozwiązaniach w oderwaniu od konkretnego języka.
Oczywiście pewne wzorce inaczej będą wyglądały w różnych językach ale idea pozostaje niezmienna.
Np. takie fasada czy fabryka... Ciężko w czystym C zaimplementować fasadę w tak czytelny sposób jak jakimkolwiek innym języku co wspiera programowanie obiektowe "wprost". Nie zmienia to jednak faktu, że wzorce projektowe można stosować nie tylko w językach OOP ale nawet w ASM czy bashu... Może będą to "potworki" wykorzystująca "idiomy"... ale jeśli projekt ma być w bash to dlaczego nie korzystać z dobrych wzorców?

2

Idiomatyczny w językach naturalnych to tyle co "tak by powiedział native speaker". Przekładając na język programowania, idiomatyczny kod to taki kod który wygląda jakby był napisany przez zawodowego programistę z dużym doświadczeniem w stosowaniu danego języka +- biblioteki.

Oczywiście ile native speakerów tyle wypowiedzi, więc idiomatyzm języka naturalnego to pewna wypadkowa. Przykładowo wsiadasz w taksówkę i mówisz "na centralny". Osoba ucząca się języka mogłaby powiedzieć "chciałbym dojechać do dworca centralnego", to też jest poprawne ale nazbyt długie i wymagające większego wysiłku. Idiomatyzm zależy też od kontekstu nastolatki mają swój slang, dresy swój.
Przenosząc to na język programowania należy oczekiwać innych idiomów u gamedev'ów a innych u korpodev'ów klepiących CRUD'y.

Przykład najprostszego idiomu w języku Java to iteracja po List<String>, osoba niezaznajomiona z językiem może napisać to tak:

for (int i = 0; i < list.size(); i++) { 
  foo(list.get(0));
}

Idiomatyczny zapis to użycie pętli for-each:

for (String s : list) {
   foo(s);
}

Inny przykład z Javy to sortowanie listy, najbardziej idiomatyczny sposób to Collections.sort(...).

Od kiedy Java 8 wprowadziła strumienie, sporo operacji typu filtrowanie czy mapowanie zapisuje się idiomatycznie przy ich użyciu.

Oprócz idiomów Javy mamy też do czynienia z idiomami bibliotecznymi. W tej chwili nie mam żadnego sensownego przykładu w głowie więc musi zostać bez przykładu.

Ostatnia strona idiomów języka to sztuczki i kruczki, przykładowo w Javie można tak (zanim wprowadzili List.of(...)):

new ArrayList<String>() {{
 put("foo");
 put("bar");
}};

Jest to bardziej trick niż idom, i ma prawo spotkać się z krytyką na code review.

0
KamilAdam napisał(a):

A co jeśli język pozwala coś zrobić na dwa sposoby (lub o zgrozo więcej), np jak C# w którym można użyć LINQu (czyli specjalnej składni do składania monad), albo można te monady flatmapować ręcznie za pomocą metody SelectMany. Czy oba sposoby mogą być idiomatyczne? Czy tylko jeden jest słuszny?

Jeśli masz na myśli LINQ methods vs LINQ syntax, to idiotmatyczne pewnie są oba, aczkolwiek drugie znacznie rzadziej spotykane, bo niezbyt zgodne z preferencjami większości (bo zwyczajnie nie pasuje do języka).

Ale na prostszym przykładzie, nieidiomatyczne jest w C# napisanie takiego kodu:

public class Ziemniak 
{
    private int waga;
    public int GetWaga() { return waga; }
    public void SetWaga(int w) { waga = w; }
}

bo w C# do opakowywania pola istnieje mechanizm właściwości:

public class Ziemniak 
{
    private int Waga { get; set; }
}

Czyli kod idiomatyczny to korzystanie z mechanizmów języka, nieidiomatyczny to zapisywanie ich przy użyciu innych mechanizmów (np. znanymi z innych języków).

several napisał(a):

Spotkałem się z tym określeniem kilka razy. Za każdym razem pochodziło to od osoby, która hobbystycznie dorabiała sobie na boku pouczając profesjonalistów jak mają programować, bądź od świeżaka świeżo po lekturze książki autorstwa takiego hobbysty.

Co dokładnie masz na myśli? Sugerujesz, że te osoby używały tego słowa nieprawidłowo, czy, że Ty piszesz nieidiomatycznie?

KamilAdam napisał(a):

hm, to czym się różnią w takim razie idiomy od wzorców projektowych lub dobrych praktyk?

Idiom - korzystanie z mechanizmów języka.
Wzorzec projektowy - powtarzalna konstrukcja z mechanizmów języka pozwalająca na rozwiązywanie powtarzalnych problemów.
Dobre praktyki - pojęcie znacznie szersze niż tylko kod, ale zarówno pisanie idiomatyczne jak i stosowanie wzorców projektowych się do nich zalicza.

2
somekind napisał(a):

Idiom - korzystanie z mechanizmów języka.
Wzorzec projektowy - powtarzalna konstrukcja z mechanizmów języka pozwalająca na rozwiązywanie powtarzalnych problemów.

Hm, czy można w takim razie powiedzieć że gettery i settery są wzorcem projektowym w Javie?
Czy można powiedzieć że Singleton nie jest wzorcem projektywym tylko idiomem w Scali?

0
KamilAdam napisał(a):

Hm, czy można w takim razie powiedzieć że gettery i settery są wzorcem projektowym w Javie?

Są powszechną praktyką, ale nie wiem, czy to aż zasługuje na miano wzorca.

Czy można powiedzieć że Singleton nie jest wzorcem projektywym tylko idiomem w Scali?

Singleton nie przestanie być wzorcem, nawet jeśli w języku jest on wbudowanym mechanizmem. Tyle, że idiomatyczne będzie użycie tego mechanizmu, a pisanie singletona samodzielnie będzie na pewno nieidiomatyczne.

0

Getter / Setter 1:1 w pola to raczej pozostałość po konwencji Java Beans używanej przez wiele bibliotek.

Sam Getter i Setter to raczej część większego podejścia (paradygmatu?) o nazwie enkapsulacja. To jest wyższy poziom abstrakcji ponad wzorcami.

Myślę że ogólnie Java Beans po tylu latach użycia jest już idomem w Javie, podobnie object w Scali jako singleton to też idiom.

1 użytkowników online, w tym zalogowanych: 0, gości: 1