Z czego wynika podobieństwo nazw "rzeczy" w językach programowania?

1

Skądinąd wiadomo, że metoda toString w Javie jest zdefiniowana w klasie Object; co za tym idzie, jest dziedziczona przez wszystkie obiekty; co za tym idzie, funkcjonalność tej metody jest dostępna w nich pod tą samą nazwą.

Metodę o nazwie toString zawiera także JavaScript. Nie wiem, na ile jest to nazwa wybrana niezależnie, a na ile zależnie od nazwy w Javie. Fakt jest faktem: nazwa jest taka sama. I podobnie do Javy – wszystko, co jest "obiektem" (np. {}), ma dostęp do funkcjonalności tej metody pod tą nazwą.

Z powyższych przykładów wynika to, że każdy obiekt lub "obiekt" w tych językach może mieć dostęp do funkcjonalności metody nazwanej tak samo. Nie wiem, na ile wynika to z chęci zachowania podobieństwa między tymi językami przez ich autorów (raczej JS do Javy), a na ile – z chęci zastosowania podobnej nazwy dla podobnej funkcjonalności.

Inny przykład: mamy operatory +, - itd. Mniej lub bardziej może być to prawda, że wszystkie języki programowania korzystające z nich dziedziczą ich formę – czyli znaki +, - itd. – z matematyki. A przynajmniej tak mi się wydaje (@jarekr000000, wiesz coś o tym?). Niemniej fakt jest faktem, że "nazwy" są takie same w wielu językach.

No, być może są jakieś języki nazywające funkcjonalność dodawania add zamiast +, ale nie pamiętam w tej chwili. Asembler? Ale nawet jeśli wziąć pod uwagę, że w danym języku występuje procedura/funkcja/podprogram add zamiast operatora + (bo np. w ogóle nie ma w nim konceptu "operatorów"), to nadal domyślam się, że nazwa add może w wielu językach znaczyć to samo – wynik dodawania liczb.

(Nie będę już podawać tutaj przykładów innych działań najpewniej dziedziczonych z matematyki, bo sądzę, że wiadomo, o co chodzi).

Być może te dwa przykłady wcale nie są takie oczywiste, lub nawet są niepoprawne – ale według mnie dobrze opisują mój problem. Otóż zastanawiam się, z czego wynika takie podobieństwo nazw. Konkretne pytania:

  1. Na poziomie danego języka programowania mógłbym zapytać: czy to, że wszystkie obiekty mogą korzystać z nazwy toString podczas wykorzystywania (opcjonalnie: definiowania) funkcjonalności zwracania swojej reprezentacji "tekstowej", wynika wyłącznie z dziedziczenia, czy zarówno z dziedziczenia, jak i z chęci zachowania podobieństwa nazw dla tych samych funkcjonalności, czy też wyłącznie z chęci zachowania podobieństwa nazw dla tych samych funkcjonalności? A może jeszcze z czegoś innego?
  2. Na poziomie międzyjęzykowym, lub nawet "międzydziedzinowym", mógłbym zapytać: czy to, że w dwóch językach programowania / dziedzinach nauki (np. informatyka i matematyka) koncepty o podobnych nazwach są definiowane podobnie (np. operator + jest definiowany podobnie tu i tu (czy nie?)), wynika wyłącznie z chęci zachowania podobieństwa między podobnymi konceptami w tych językach / dziedzinach, czy też z tego oraz czegoś innego, czy też wyłącznie z czegoś innego?

Jeśli coś napisałem zbyt trudno, chętnie wyjaśnię.


PS. Może doprecyzuję punkt nr 1: mogę sobie wyobrazić, że w danym języku programowania różne klasy miałyby zadeklarowane metodę o funkcjonalności zwracania reprezentacji "tekstowej" swoich obiektów pod różnymi nazwami. I na przykład byłoby w nim tak, że obiekt klasy String miałby metodę stringToString, a obiekt klasy Object miałby metodę objectToString. Niby nazwy podobne – ale już nie takie same. Ewentualnie mogłyby być jeszcze bardziej inne – na przykład stringToString oraz getMeAsString. Albo w ogóle niezwiązane ze słowem (ciągiem znaków) string.*


PS2. * Więc mogę sobie coś takiego wyobrazić, ale w rzeczywistości widzę, że w Javie i JavaScripcie mamy toString dla wszystkich obiektów. Zastanawiam się więc, z czego to dokładnie wynika.


UPDATE: Interesowałyby mnie także wszelkie zasady i reguły w programowaniu czy inżynierii oprogramowania (np. tzw. principles), które byłyby związane z tym problemem. Obecnie nie wiem o żadnej.

2

Ad 1.:
W wymienionych przez Ciebie językach — prawie wyłącznie z dziedziczenia. Musisz mieć toString (bo dziedziczysz), a jak już masz, to po co potem dublować? Ale mógłbyś, jeśli Cię mocno ciśnie…

Ad 2.:
Niemal zawsze z chęci. Czasami może być konieczne, gdy chcemy zachować kompatybilność z czymś już istniejącym (np. wczesny C++ i C), ale ogólnie ludzie starają się nie wymyślać koła na nowo… zbyt często. Bo wciąż wciąż jak piszesz coś funkcyjnie, to musisz sobie przeczytać, jak nazywa się filter, jak map, jak Maybe

1

Inny niż co? - Silv 5 minut temu

Inny niż Java.

Jest raczej zasadą w językach "kompilowanych", czyli bardziej formalnie "statycznie typowanych", że aby 'toString()' było <ważne>, klasa MUSI dziedziczyć w tym przypadku po Object.
W językach dynamicznych bywa/jest inaczej. "Aha, więc masz metodę 'toString', więc pasujesz do nas", rzeczywiste dziedziczenie jest nieważne / mniej ważne

jest dużo materiałów, np tu:
https://developer.mozilla.org/pl/docs/Web/JavaScript/Wprowadzenie_do_programowania_obiektowego_w_jezyku_JavaScript
https://www.programcreek.com/2014/02/java-vs-javascript/

5

Przykłady nazewnicze:
COBOL

ADD WS-NUMA WS-NUMB WS-NUMC TO WS-NUMD GIVING WS-NUME

LISP - poczytaj o car,cdr, cons (to akurat operacje na listach) - chodzi o nazwy z księżyca, pasujące zupełnie do niczego (ale jest historia tłumacząca ich pochodzenie)

Haskell statycznie typowany , kompilowany, - nie ma dziedziczenia (*), nie ma toString - jest typeclass Show :-)

(*) - jest dziedziczenie, ale oznacza co innego niż w javie, jest też polimorfizm, ale ... inny

IMO - 1. nie ma żadnej spójności nazw nawet w ramach jezyka, często widziałem operacje toX, ... a kawałek dalej w innej bibliotece asX.
IMO - 2 programiści nie lubią zapamietywać zbyt wielkiej ilosci rzeczy, więc jak ktoś przeskakuje miedzy jezykami to tworząc np. bibliotekę, tworząc nowy jezyk wybierze nazwy metod, które już zna. Kolejni programiści też chętniej wybiorą rozwiązanie - choć trochę podobne do tego co znają (JS story).

Ogólnie to nie rozumiem o co Ci chodzi nawet.

Tak naprawdę istnieje poważna dyskusja na wyższym poziomie o tym jakie teorie, jakie języki programowania tworzymy, z jakiego rodzajami struktur, gramatyki - i czy to co tworzymy nie wynika po prostu z ograniczeń ludzkiego, mózgu - pojmowania. Tu fajnie czasem opowiada na ten temat Bartosz Milewski -https://corecursive.com/category-theory-is-how-our-minds-work-with-bartosz-milewski/

0

@Althorion:

Ad 1. Czyli tak ogólnie można powiedzieć, że twierdzisz, że to struktura/"typ" języka definiuje podobieństwo nazw w nim? Czyli jakby w danym języku nie było dziedziczenia (w ogóle), to nikt nie pokusiłby się o zdefiniowanie "czegoś innego", żeby tylko wymusić podobieństwo nazw dla każdego obiektu?

Ad 2.

ogólnie ludzie starają się nie wymyślać koła na nowo

To stwierdzenie mi się podoba. Być może odpowiada w jakiejś części na mój problem.


@AnyKtokolwiek:

Jest raczej zasadą w językach "kompilowanych", czyli bardziej formalnie "statycznie typowanych", że aby 'toString()' było <ważne>, klasa MUSI dziedziczyć w tym przypadku po Object.

Powiedzmy, że to zrozumiałe (choć ująłeś to dość oględnie); w takim razie jesteś za tym (co też w akapicie wyżej przypisuję @Althorion), że to struktura/"typ" języka definiuje podobieństwo nazw w nim, tak?

Podoba mi się Twoje rozróżnienie między językami statycznie a dynamicznie typowanymi. Między innymi o takie rozróżnienia mi chodzi, gdy pytam o "powody", dla których nazwy są takie same.


@jarekr000000:

Wielkie dzięki za przykłady – lubię poszerzać światopogląd programistyczny o inne języki. :)

Piszesz, że nie rozumiesz, o co mi chodzi. A jednak w ostatnim akapicie trafnie ująłeś moje wątpliwości (których sam nawet tak ująć nie potrafiłem), tzn. tak:

(…) istnieje poważna dyskusja (…) czy to co tworzymy nie wynika z ograniczeń ludzkiego, mózgu - pojmowania.

Wywiad z Bartoszem zobaczę. Piszesz ponadto, że:

IMO - 1. nie ma żadnej spójności nazw nawet w ramach jezyka, często widziałem operacje toX, ... a kawałek dalej w innej bibliotece asX.

OK, to wnosi do dyskusji od innej strony, niż ja celuję: że jakkolwiek są przykłady, że jest pewne podobieństwo w języku, to są też przykłady, że go nie ma.

1

Wydaje mi się to szukaniem filozofii na siłę. ;)
Co do toString w JS i Javie, to w firmie Netscape jak robili JS to też współpracowali z firmą Sun nad integracją z Javą (applety), a jednocześnie pierwszy JS był zrobiony w bardzo ekspresowym tempie. Jeśli była w tym jakaś zasada programowania, to chyba brak czasu na przesadne kombinowanie.

3

Już całkiem zatraciłem ideę, o co Ci właściwie chodzi i o co tak naprawdę pytasz…

Języki programowania czemuś służą. One nie są wymyślane (no, przynajmniej te popularne…) „bo się komuś nudziło”, tylko żeby móc wyrażać idee (algorytmy) w sposób zrozumiały i dla ludzi, i dla maszyn. Maszyny nie mają żadnych paradygmatów, z góry założonych koncepcji, więc im jest to obojętne, ale ludzie wręcz przeciwnie. Ludzie nie zaczynają tworzenia języków programowania w kołysce, lecz już na pewnym etapie w swoim życiu, gdzie naoglądali się pewnych idei i przyswoili je sobie — tego jakie są operatory matematyczne i jak się je oznacza, jakie są ogólne paradygmaty programowania, jak wygląda kod i rozwiązania w innych językach. I z tą wiedzą przychodzą i z nią zaczynają tworzenie czegoś swojego.

Więc za każdym razem tam, gdzie się z czymś już spotkali wielokrotnie w swoim życiu, mają tendencję do używania już sprawdzonego rozwiązania. Nie ma obiektywnych przesłanek, dla którego to + miałby oznaczać dodawanie, a nie na przykład . Maszynie jest to obojętne, ale ludziom nie. Bo ci ludzie już wcześniej się spotkali z koncepcją dodawania i symbolu + to dodawanie reprezentującego.

Jak się pojawia jakieś nowe określenie, to albo dlatego, że określa coś nowego (więc jeszcze nie nazwanego) — no, przynajmniej autor nie wiedział, że ktoś to nazwał przed nim, więc tej nazwy jeszcze nie przyswoił; albo dlatego, że autor ogólnie przyjętej nazwy nie lubi i chce coś nazwać po swojemu.

I to powiedziawszy, pewne paradygmaty programowania, w szczególności właśnie programowanie obiektowe, narzuca dosyć silnie konsekwencję w nazewnictwie. Jednym z takich mechanizmów jest właśnie dziedziczenie — jeśli klasa-matka ma jakieś atrybuty/metody, to klasy potomne też je muszą mieć. Taka jest właśnie idea dziedziczenia.

2

Haskellowe typeclass i go duck typing pokazuje, że można WYMUSIĆ spójne nazewnictwo bez dziedziczenia.

W go jest to trochę na opak - bo jak masz spójne nazewnictwo to możesz korzystać z polimorfizmu.
Natomiast haskellowy typclass całkowicie oddziela obiekt/ (typ danych) od jego "zachowania". To troszkę jakbyś w języku obiektowym dodawał wrapper/ adapter do istniejących klas) - co też oznacza, że możesz dodawać "interfejsy" do zupełnie cudzych typów danych, których kodu nie możesz zmieniać.

0

@xy:

Wydaje mi się to szukaniem filozofii na siłę. ;)

Oczywiście, możesz tak to nazwać. Moim zdaniem jednak jest to coś przeciwnego: jest to "szukanie filozofii" z dostępnego "zbioru filozofii".

Co przez to rozumiem? Przykładowo widzę jakiś język programowania i pytam: czemu każdy obiekt ma tę samą metodę? Powody, dla których tak jest (czyli np. zastosowanie mechanizmu dziedziczenia, próba upodobnienia do innego języka, fantazja twórców) opisują właśnie jakby swoistą "filozofię" twórców tego języka. Są tym samym są częścią owego "zbioru filozofii". Dopuszczam przy tym powód "brak powodu"; tylko niech on będzie dobrze umotywowany, nie że "tak już jest" lub "nie dowiemy się, co myśleli twórcy".

Poznawszy (jakiekolwiek? pewne? wszystkie?) filozofie stojące za podobieństwem nazw "rzeczy" w różnych językach, będę mógł powiedzieć, że ten wątek się wyczerpał (czyli jakby "problem został rozwiązany", choć tu nie chodzi oczywiście o "problem" sensu stricto). Biorąc pod uwagę oględność terminu "filozofia", jest raczej bardziej prawdopodobne, że prędzej stracę zapał do czytania odpowiedzi, niż że rozwieję wszystkie swoje wątpliwości. ;)

Jeśli była w tym jakaś zasada programowania, to chyba brak czasu na przesadne kombinowanie.

Widzisz, to jest właśnie taka myśl, która odpowiada na moje wątpliwości. Jeśli to rzeczywiście były "kwestie biznesowe" (mówiąc oględnie), to by można powiedzieć, że one z kolei mogły wymusić wykorzystanie jakichś ogólnodostępnych wzorców. Albo były to wzorce nieznane autorom (poszukali i znaleźli), albo znane (nauczyli się ich wcześniej i je po prostu znali).


@Althorion:

Nie pisz, że zatraciłeś ideę. Piszesz przecież dalej coś, co odpowiada na moje wątpliwości. :) I tak:

Języki programowania czemuś służą. One nie są wymyślane (no, przynajmniej te popularne…) „bo się komuś nudziło”, tylko żeby móc wyrażać idee (algorytmy) w sposób zrozumiały i dla ludzi, i dla maszyn.

A te idee – czy algorytmy – jak według Ciebie korespondują z podobieństwem nazw?

Więc za każdym razem tam, gdzie się z czymś już spotkali wielokrotnie w swoim życiu, mają tendencję do używania już sprawdzonego rozwiązania.

"Sprawdzonego", czyli "dobrego" (dla kogo?)?

Nie ma obiektywnych przesłanek, dla którego to + miałby oznaczać dodawanie, a nie na przykład ⋈.

Jednak mam tu wątpliwości. Z drugiej strony – mogę sobie wyobrazić, że nie zawsze da się (przekonująco) wyjaśnić, czemu takie a nie inne symbole zostały użyte w takich a nie innych kontekstach, na przykład w matematyce. Ale mnie tu idzie raczej o podobieństwo, a nie o pochodzenie nazw (w tym sensie symbole uważam za nazwy).

Bo ci ludzie już wcześniej się spotkali z koncepcją dodawania i symbolu + to dodawanie reprezentującego.

Czyli ponownie, jak to już było w tym wątku poruszane – ktoś coś zna, więc z jakichś powodów tę znajomość wykorzysta w konkretnym przypadku. Przykład: ktoś znał pewną metodę w języku programowania X, więc wykorzystał ją w języku programowania Z. Ale dlaczego ją wykorzystał?

Staje się to jeszcze bardziej widoczne, gdy założymy, że mógł ten ktoś znać dwa języki programowania: X oraz Y. Tworząc nowy język Z, wykorzystał metodę z języka X. A dlaczego nie z języka Y? Czy język X miał jakieś przewagi nad językiem Y?

Może w typie w rodzaju danego języka (termin "typ" jest zbyt wieloznaczny, dlatego zmieniłem) wykorzystanie metody o nazwie toX (np. w "języku obiektowym") jest po prostu zawsze "lepsze", tj. lepiej odpowiada na przykład wymaganiu intuicyjności stawianemu przez użytkowników języka (lub przez twórców, przewidujących wymagania jego użytkowników)? Może lepiej odpowiada na inne wymagania: prostoty, uprzedniej znajomości, łatwości wpisywania z klawiatury (niewątpliwie (?) szybciej wpisać toString niż getMyStringRepresentation; pomijam tu na moment autouzupełnianie przez IDE)?

A propos ostatniego zdania, wydaje mi się, że jest jakiś język (niejeden?), który właśnie krótkie nazwy (funkcji?) preferował z powodów użytkowych.

Jak się pojawia jakieś nowe określenie, to albo dlatego, (…); albo dlatego, że autor ogólnie przyjętej nazwy nie lubi i chce coś nazwać po swojemu.

No właśnie, to by ucinało jednak dyskusję o takim języku (choć nie pasuje mi to, jak wyżej napisałem w tym poście), bo kto powie, co myślał autor? Ale nie chciałbym tutaj koncentrować się na danych językach, więc mam nadzieję, że da się uniknąć takich ślepych uliczek.

I to powiedziawszy, pewne paradygmaty programowania, w szczególności właśnie programowanie obiektowe, narzuca dosyć silnie konsekwencję w nazewnictwie.

…O czym właśnie przed paroma akapitami wspomniałem – tylko nie przeczytawszy wtedy jeszcze tego Twojego zdania. ;)

Jednym z takich mechanizmów jest właśnie dziedziczenie — jeśli klasa-matka ma jakieś atrybuty/metody, to klasy potomne też je muszą mieć. Taka jest właśnie idea dziedziczenia.

Czyli jakby mielibyśmy tu jedną odnogę moich wątpliwości rozwiązaną. W językach z dziedziczeniem (wszystkich? mam wątpliwości) popularność nazw (przez "popularność" rozumiem tu podobieństwo, jako że użycie nazwy dla każdego obiektu w danym programie rozumiem jako oddzielny przypadek) wynika z mechanizmu niezwiązanego z nazwami… A może właśnie związanego? Czy podstawą dziedziczenia nie jest zachowanie tych samych konceptów w każdej klasie potomnej? A czy to nie znaczy, że – automatycznie – nazwy tych konceptów muszą być (=są) zachowane w tych klasach? Co by oznaczało – gdyby to była prawda – że pośrednio dziedziczenie miałoby też na uwadze występowanie podobnych (no, takich samych, można chyba powiedzieć) nazw w każdym obiekcie, a nie tylko występowanie tych samych funkcjonalności.


@jarekr000000: dzięki znów za przykłady. :)


PS.

Myślę, że napiszę, skąd mi się ten problem wziął. Otóż tworzę sobie nową wersję mojego artykułu ze wskazówkami, jak pisać artykuły; związałem go wcześniej z koncepcjami z procesu tworzenia oprogramowania, a teraz jeszcze troszkę mocniej chcę go z nimi związać.

I mam tam taką wskazówkę:

  1. Choose the words that you already use.

Nie wchodząc w szczegóły, co przez to rozumiem: pomyślałem sobie, że jest to podobne do programowania. W programowaniu używamy na przykład tych samych nazw na metody o podobnych funkcjonalnościach (toString, czy też bardziej ogólnie: toSomething).

Zacząłem się więc zastanawiać, jak jedno z drugim można połączyć. Może jest jakaś reguła, która by mówiła, na przykład: "W programowaniu należy wykorzystywać podobne nazwy metod", albo: "Język programowania powinien być tworzony tak, by był podobny do innego", albo: "Czytelny kod uwzględnia występowanie podobnych nazw podobnych konceptów", albo coś innego. Nie znam żadnej takiej, więc postanowiłem założyć wątek; a nuż ktoś inny będzie znać?

Ale, jak widać z dyskusji, poszła ona w trochę inną stronę. Może to i dobrze? Nową wersję artykułu i tak mam nadzieję stworzyć, z tą wskazówką czy też bez. A może właśnie dyskusja jako taka będzie bardziej wartościowa od tego mojego trochę prowincjonalnego problemu.

4

Szukasz analogii na siłę. Niektóre języki mają podobne słowa kluczowe/API bo jeden powstawał na bazie drugiego plus autorzy chcieli ułatwić wejście w daną technologię ludziom przechodzącym z innej. Przykładów na brak takiej spójnosci jest tyle samo co na jej występowanie. Piszesz o toString ale już taki python ma str()/repr() a C# ma ToString. Znajdziesz masę języków gdzie hashmapa to map (np. Java i C++) ale już w Pythonie czy .NET to dict/dictionary. Trochę jak z benchmarkami, jak się uprzesz to udowodnisz dowolną tezę ;)

1

W przypadku JavaScriptu myślę, że bardziej trafne byłoby stwierdzenie, że obiekty mogą zaimplementują pewien interfejs, który wyraża się w tym, że implementują metodę toString.

Co prawda w JavaScript nie ma na poziomie języka "interfejsów", ale od strony samej koncepcji chodzi o to, że obiekt może implementować daną metodę, a może jej nie implementować, niezależnie od tego, czy obiekt dziedziczy z Object, czy nie.

const foo = Object.create(null); // obiekt niedziedziczący z niczego
foo.toString = () => 'kotek'; // implementuje "interfejs"
console.log(foo + ''); // kotek

Co ciekawe do JSa są dodawane kolejne magiczne metody, ale te nowe magiczne metody są już oznaczane nie za pomocą stringów, ale za pomocą symboli (well-known symbols)

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

Co do dziedziczenia, to jak ktoś mówi coś o dziedziczeniu, to muszę sobie tłumaczyć w myślach, bo w większości przypadków dziedziczenie to szczegół implementacyjny, a nie coś istotnego. Ew. wzorzec projektowy, który czasami się może przydać. A samą koncepcję da się wyrazić bardziej celnie przez koncepcję "implementacji interfejsu" (niezależnie od tego, czy interfejs jest w języku, czy jest osiągany przez duck typing). Ew. poprzez kompozycję (zależy o jakim kontekście mowa).

Inny przykład: mamy operatory +, - itd. Mniej lub bardziej może być to prawda, że wszystkie języki programowania korzystające z nich dziedziczą ich formę – czyli znaki +, - itd. – z matematyki.

Tak samo tutaj. Programowanie nie jest potomkiem matematyki, tylko inspirowane matematyką. I nazewnictwo dlatego jest podobne.

Swoją drogą jak nazwać koncepcję "inspiracji czymś"? Np. JavaScript jest inspirowany (niestety i trochę na siłę) Javą, choćby w samej nazwie, jak i w pewnych dziwnych rzeczach (jak nieszczęsny obiekt Date).

Myślę, że można to nazwać wirusowością. Koncepcje mogą przeskakiwać z jednego języka na drugi. Co może być pozytywne, bo wzbogaca języki o nowe funkcje, ale czasem języki mogą przyjmować rzeczy z innych języków, które są negatywne, ew. po prostu niepotrzebne. I język się psuje przez to. Co prawda z czasem języki nabywają przeciwciała (np. większość języków jest już odporna na instrukcję goto), ale raczej wolno to trwa. Obecnie istnieje wiele idei, które nie są złe, ale które są strasznie nadużywane (np. idea statycznego typowania, idea dziedziczenia klasowego itp.) i kolejne języki się tym infekują.

Co do samego dziedziczenia natomiast, to często dostrzegam dziedziczenie w sensie "spadku po kimś", a nie to biologiczne. Czyli bardziej legacy. Wiadomo jak wygląda kod legacy, że jest tam mnóstwo niepotrzebnych rzeczy, dług techniczny odziedziczony po wcześniejszych programistach (albo po nas samych, ale na to samo wychodzi, bo pisząc go byliśmy innymi ludźmi i mniej wiedzieliśmy o projekcie). Tak samo JavaScript jako język ma mnóstwo dziwnych rzeczy, które są i będą, bo jakby je usunąć z języka, to połowa stron przestałaby działać. Więc i TypeScript też ma te dziwne rzeczy, niejako odziedziczył je (w formie spadku) z JavaScriptu (więc dopóki TS nie zerwie z kompatybilnością wsteczną w stosunku do JSa, to dalej będzie to tylko nakładka na JS).

2

Nie czytałem całego wątku, ale podobieństwo słów kluczowych wcale nie musi oznaczać, że oznaczają to samo. Dla przykładu:

  • typeclassy z Haskella są w Haskellu pod nazwą class, w Ruście pod nazwą trait
  • class w Javie, C#, C++, Scali, Kotlinie, etc oznacza natomiast klasę w ujęciu OOP
  • trait w Scali to coś pomiędzy klasą i interfejsem w Javie, a nie odpowiednik Rustowego traita
  • sealed w C# używa się do klas (wtedy to blokuje dziedziczenie) i metod (wtedy blokuje nadpisywanie) i semantycznie działa tak jak final z Javy w tych samych przypadkach. Jednak sealed w Scali można użyć tylko na klasach i nie blokuje on całkiem dziedziczenia, a tylko ogranicza do obecnego pliku
  • object w Scali służy do definiowania singletona, w C# jest tym samym co Javowy Object czyli nadklasą wszystkich typów referencyjnych
  • itp itd
1

Ad. 1.

Ja sądzę, że to głównie wynika z tego, że chcemy mieć jakąś formę współdzielenia interfejsu, tak, że użytkownik nie musi zawsze wiedzieć na jakim obiekcie operuje. To jest ogólnie znana i używana zasada już z czasów Uniksa (patrz FD). Ma to swoje zalety w postaci tego, że można wymienić jedną implementację na drugą bez zmiany samego kodu (LSP).

Ad. 2.

Nazwy różnych rzeczy są współdzielone między językami IMHO głównie z powodu przyzwyczajeń. Jeśli wiemy, że w wszędzie indziej ciąg znaków jest nazywany stringiem, to niespecjalnie opłaca się wymyślać nazwę na nowo. Pozwala to nowym programistom przełożyć przynajmniej część wiedzy z innych języków do nowego. Dla tego często języki jak Haskell potrafią być problematyczne, bo mają zupełnie inną terminologię, która potrafi początkowo ogłuszyć.

0

@Shalom:

Szukasz analogii na siłę.

Trochę jak z benchmarkami, jak się uprzesz to udowodnisz dowolną tezę ;)

Ważne dla mnie, żeby było to jasne w tej dyskusji: nie chciałbym upierać się, by udowadniać jakąś tezę (swoją czy nie swoją). :) Mam nadzieję, że to tylko tak wygląda (z pozoru), i że to wina tego, że nie umiem się wysłowić tak, jakbym chciał.

Co chciałbym natomiast? Postawić pytania – już postawiłem; a dalej: wejść w ciekawą dyskusję na ich podstawie, przy okazji odpowiadając na nie (= rozwiązując problem, który opisują). Jeśli pytania są źle sformułowane (ja sądzę, że dobrze, ale to nie ja oceniam), wyjaśnię jeszcze: chodzi mi o szukanie (może: o znalezienie). O odkrycie (odkrywanie?) prawidłowości w postępowaniu przy wyborze nazw w językach programowania. Przy okazji chciałbym rozwiązać swój raczej prowincjonalny problem (pisałem o nim w poście bezpośrednio przed Twoim, w postscriptum).

W związku z powyższym bez zastrzeżeń merytorycznych przyjmuję jako argument w dyskusji Twoją tezę o niepowiązaniu w niektórych przypadkach znaczenia nazw z "narzuceniem" ich podobieństwa. Skoro tak uważasz, to tak może być. Nie mam większego komentarza; cóż, może jeszcze do tego wrócę w dalszym biegu wątku. Szukam dalej. :) Dzięki. :)


@LukeJL:

Co do dziedziczenia, to jak ktoś mówi coś o dziedziczeniu, to muszę sobie tłumaczyć w myślach, bo w większości przypadków dziedziczenie to szczegół implementacyjny, a nie coś istotnego. Ew. wzorzec projektowy, który czasami się może przydać. A samą koncepcję da się wyrazić bardziej celnie przez koncepcję "implementacji interfejsu" (niezależnie od tego, czy interfejs jest w języku, czy jest osiągany przez duck typing). Ew. poprzez kompozycję (zależy o jakim kontekście mowa).

Ciekawe: jak ja o tym teraz myślę w ten sposób, to dla mnie chyba dziedziczenie jest bardziej naturalne od implementowania interfejsu. Jest dla mnie na pewno intuicyjne, że klasa dziedzicząca jest nadzbiorem zbioru funkcjonalności klasy bazowej, pewnym "opakowaniem", jak wkładanie pudełka w pudełko.

Programowanie nie jest potomkiem matematyki, tylko inspirowane matematyką. I nazewnictwo dlatego jest podobne.

Generalnie nie wiem, czy w tej dyskusji ma dla mnie znaczenie rozróżnienie między "byciem potomkiem" matematyki, a inspiracja nią. Co by zmieniało, gdyby tak rozróżniać? Efekt jest taki sam, prawda?

Koncepcje mogą przeskakiwać z jednego języka na drugi.

Dobre podsumowanie części zdań w tej dyskusji.


@Wibowit: czyli nie wprost masz na myśli, że jest inny cel, czy: inne cele, tworzenia nazw w językach programowania niż podobieństwo, dobrze rozumiem? Czyli coś przeciwnego do mojego założenia z pierwszego posta wątku. Jeśli dobrze Cię zrozumiałem: miałbyś pomysł, jak go (je) ująć?


@hauleth:

Ja sądzę, że to głównie wynika z tego, że chcemy mieć jakąś formę współdzielenia interfejsu, tak, że użytkownik nie musi zawsze wiedzieć na jakim obiekcie operuje.

To jest bliskie tego, co mi się wydaje; że jest jakaś zasada bardziej "inżynierska", która motywowałaby wybór nazw. Spojrzenie warte odnotowania.

To jest ogólnie znana i używana zasada już z czasów Uniksa (patrz FD).

Co to jest "FD"? Jedyne, co przychodzi mi do głowy, to file descriptor, ale nie widzę powiązania.

Dla tego często języki jak Haskell potrafią być problematyczne, bo mają zupełnie inną terminologię, która potrafi początkowo ogłuszyć.

Czemu mają inną? Masz/znasz jakieś powody?

0

Brzmi to trochę jakbyś poszukiwał platońskiego języka programowania będącego inspiracją dwa wszystkich innych języków programowania

Silv napisał(a):

Inny przykład: mamy operatory +, - itd. Mniej lub bardziej może być to prawda, że wszystkie języki programowania korzystające z nich dziedziczą ich formę – czyli znaki +, - itd. – z matematyki. A przynajmniej tak mi się wydaje (@jarekr000000, wiesz coś o tym?). Niemniej fakt jest faktem, że "nazwy" są takie same w wielu językach.

Ale dla potęgowania już tak dobrze nie ma, czasem jest ^, czasem **, a czasem funkcja pow, lub z jakiegoś powodu nawet tego nie ma i trzeba używać kombinacji funkcji exp i log.
Zresztą niektóre języki miały tez inne operatory na dodawanie, ML - +. dla liczb zmiennoprzecinkowych, Forth +2 dla liczb podwójnej precyzji, a Clojure ma +' dla dodawania z przepełnieniem

0

Brzmi to trochę jakbyś poszukiwał platońskiego języka programowania będącego inspiracją dwa wszystkich innych języków programowania.

Nie pamiętam/znam wiele z Platona, ale chyba wypada sobie odświeżyć/poznać, bo na tym forum już kilka razy widziałem do niego odniesienia w ostatnich miesiącach. (Piszę to serio).

Ale nie, nie szukam jednego języka programowania będącego inspiracją wszystkich innych… Niemniej być może szukam czegoś podobnego. W zasadzie wolałbym twierdzić, tak od strony filozoficznej, że niczego konkretnego nie szukam… Ale, jeśli mówić konkretnie, to chodzi mi o potwierdzenie lub obalenie hipotezy, że występowanie podobnych nazw "rzeczy" w językach programowania ma uzasadnienie. Jedno takie uzasadnienie – będzie to jeden dowód. W wątku pojawiło się już parę propozycji takiego uzasadnienia. Natomiast jedno uzasadnienie dla występowania różnych nazw (czyli że można mieć cel w stosowaniu nazw innych niż gdzie indziej dla samej ich inności) będzie jednym* dowodem na jej fałszywość.**


PS. * Dodałem słowo "jednym", bo wiadomo – nie "ostatecznym".


PS2. ** W wątku pojawiło się parę propozycji dowodów też tego.

2

Natomiast jedno uzasadnienie dla występowania różnych nazw (czyli że można mieć cel w stosowaniu nazw innych niż gdzie indziej dla samej ich inności) będzie dowodem na jej fałszywość.

"Wszyscy" nazywają funkcje map() i filter(), a w C# są to Select() i Where() - nie wiem czy to zostało nazwane stricte dla inności od języków funkcyjnych, ale zostało nazwane z uwagi na "znajomość" pojęć SQL-owych.

3

Podobieństwa...? To dlaczego zwracanie długości tablicy/wektora/czegokolwiek to

  • W C++ std::array i std::vector ma size
  • W Javie i JavaScript jest length
  • W Pythonie wywołuje się len by wywołać magiczną metodę __len__
  • W Ruście odpala się metodę len()

A może by coś dodać do wektora...? Sure, waćpanie

  • W C++ mamy push_back
  • Java ma add
  • W JavaScript jest push
  • W Pythonie append

Ja mam akurat odwrotne wrażenie: nikt nie używa spójnego nazewnictwa i zawsze jak wracam do języka, w którym miałem ze dwa lata przerwy, to muszę sobie przypominać czego się używa.

1
Silv napisał(a):

@Wibowit: czyli nie wprost masz na myśli, że jest inny cel, czy: inne cele, tworzenia nazw w językach programowania niż podobieństwo, dobrze rozumiem? Czyli coś przeciwnego do mojego założenia z pierwszego posta wątku. Jeśli dobrze Cię zrozumiałem: miałbyś pomysł, jak go (je) ująć?

Czasami powody dla nazewnictwa są marketingowe. Dla przykładu Java powiela słowa kluczowe z C++, natomiast w Ruście mocno napracowali się, by jak najmniej słów kluczowych pokrywało się z Javą. Wielu ludzi gardzi OOPem, zwłaszcza takim Javowym i chyba tacy ludzie mają duży wpływ na postać Rusta. C# to niby "Java done right", a więc dużo słów kluczowych się pokrywa.

Każdy język programowania bierze trochę pomysłów z innych i tworzy swój unikalny miks wzbogacony o mniej lub więcej nowości. Poparz tutaj https://doc.rust-lang.org/reference/influences.html albo np na https://en.wikipedia.org/wiki/Java_(programming_language) gdzie widać:

Influenced by
Ada 83, C++,[3] C#,[4] Eiffel,[5] Mesa,[6] Modula-3,[7] Oberon,[8] Objective-C,[9] UCSD Pascal,[10][11] Object Pascal[12]
Influenced
Ada 2005, BeanShell, C#, Chapel,[13] Clojure, ECMAScript, Fantom, Gambas,[14] Groovy, Hack,[15] Haxe, J#, Kotlin, PHP, Python, Scala, Seed7, Vala

Nie powinno dziwić, że sporo rzeczy się pokrywa.

0

@Ktos:

"Wszyscy" nazywają funkcje map() i filter(), a w C# są to Select() i Where() - nie wiem czy to zostało nazwane stricte dla inności od języków funkcyjnych, ale zostało nazwane z uwagi na "znajomość" pojęć SQL-owych.

Więc przywołujesz argument, jakoby w tym przypadku (?) wyznacznikiem podobieństwa nazw było podobieństwo konceptów, jeśli dobrze rozumiem (to była jedna z moich propozycji w pierwszym poście).


@Spearhead:

Zauważ jednak, że:

  • size jest powszechnie używaną nazwą, więc można tłumaczyć wykorzystanie tego podobieństwem konceptów.
  • size i length jednak się różnią, bo jedno odnosi się do tablicy, drugie do napisu. Jednak moje pytanie: czy jest to wystarczające rozróżnienie dla uzasadnienia tej różnicy w nazwach?
  • len to najpewniej skrót od length, więc pod pewnym kątem patrząc można odczytywać jako tę samą nazwę (z ograniczoną długością z uwagi na jakieś inne ograniczenia).
  • push_back jest podobne do push, add i append, więc odczytuję to jako różne nazwy na opisanie dość podobnych konceptów, a to prawie to samo co jedna nazwa dla mnie (mam w szczególności w głowie tę tabelkę nazw metod double-ended queue w różnych językach: https://en.wikipedia.org/wiki/Double-ended_queue#Operations). Ale tu moglibyśmy się spierać, czy ważniejsze jest podobieństwo konceptów dla wyjaśnienia podobieństwa nazw, czy podobieństwo nazw dla wyjaśnienia podobieństwa konceptów… Nie chciałbym odbiegać od tematu dyskusji za daleko, ale jednak mogę na ten temat więcej napisać swoich przemyśleń, gdybyś chciał. :)

@Wibowit:

Czasami powody dla nazewnictwa są marketingowe.

Rozumiem. Już taka teza w wątku się pojawiła. Nie pasuje mi to trochę, taki cierń; jednak wolałbym mieć naukowe – czyt. informatyczne, bo w sumie marketing też jest oparty na pewno na jakichś naukach – uzasadnienia dla konceptów tak ścisłych jak języki programowania. Ale może samo pojęcie "języków programowania" powinienem przewartościować? Że nie wszystko w nich musi mieć odpowiedniki bardziej inżynierskich DRY, YAGNI, SOLID?

0
Silv napisał(a):

@Wibowit:

Czasami powody dla nazewnictwa są marketingowe.

Rozumiem. Już taka teza w wątku się pojawiła. Nie pasuje mi to trochę, taki cierń; jednak wolałbym mieć naukowe – czyt. informatyczne, bo w sumie marketing też jest oparty na pewno na jakichś naukach – uzasadnienia dla konceptów tak ścisłych jak języki programowania. Ale może samo pojęcie "języków programowania" powinienem przewartościować? Że nie wszystko w nich musi mieć odpowiedniki bardziej inżynierskich DRY, YAGNI, SOLID?

Własny język może stworzyć każdy i kierować się zasadami jakie mu się żywnie podobają. Ziomki od GraalVMa przygotowali język demonstracyjny od przerabiania którego możesz zacząć tworzenie swojego: https://github.com/graalvm/simplelanguage

Nawet nasz forumowy kolega @Patryk27 stworzył własny język: Kompilator SScript Może nam powie jakie idee mu przyświecały, gdy go tworzył (o ile jakiekolwiek konkretne były)?

1
Silv napisał(a):
  • size i length jednak się różnią, bo jedno odnosi się do tablicy, drugie do napisu. Jednak moje pytanie: czy jest to wystarczające rozróżnienie dla uzasadnienia tej różnicy w nazwach?

W Javie length odnosi się do tablicy a size do kolekcji. Sensu w tym żadnego nie widzę

1

Może nam powie jakie idee mu przyświecały, gdy go tworzył (o ile jakiekolwiek konkretne były)?

Idee nie dość, że istniały, to były wysoce nietuzinkowe - otóż nudziło mi się :-P

Chciałem się rozwijać, lecz jednocześnie nie miałem pomysłu na żadne użyteczne projekty - padło zatem na stworzenie własnego języka (coś w stylu nie wiesz o czym pisać? pisz o pisaniu, so meta).

Prawdopodobnie nie trudno zauważyć, że językowi nie przyświecały żadne motta - ani on zwięzły, ani nie rozwiązuje żadnego ciekawego problemu; tym niemniej sama nauka budowy kompilatorów oraz maszyn wirtualnych (bez napisania ani jednego testu, bo przecież "mój kod działa prawidłowo") była niezwykle interesująca i polecam taką podróż każdemu; oczywiście tuż obok napisania własnego raytracera, systemu operacyjnego (wyderos zza niebios) czy klepnięcia apki w OpenGLu.

</offtop>
0

Ktoś tu pisał już że widzi więcej różnic niż podobieństw i ja się z nim zgadzam. Spójrzmy na Monadę :D

  • Na Wikipedii jest jakiś dziwny tekst o funkcjach unit (która służy do tworzenia monady) i bind (która jest główną funkcjonalnością monady)
  • W Scali jest metoda flatmap zamiast bind. Co do tworzenia bywa różnie, ale jeśli jest tylko jedna metoda tworząca to jest to zwykle apply. Obie nazwy wynikają z lukru składniowego Scali
  • W Haskellu jest funkcja return do tworzenia monady oraz operator >>=, który robi to co funkcja bind
1

Nie przeczytałem całego wątku, więc możliwe że będę powtarzał kogoś:
Ad 1) W większości wysokopoziomowych języków masz mechanizmy abstrakcji. Te mechanizmy sprowadzają się zazwyczaj do kontraktu (specyfikacji) i implementacji. Aby taki mechanizm miał sens, musisz mieć możliwość wymuszania zgodności kontraktu ze specyfikacją, na najbardziej podstawowym poziomie musisz wiedzieć, który kontrakt wypełnia dana implementacja, czyli musisz rozwiązać problem mappingu. Optymalnym rozwiązaniem tego problemu (np. w sensie Kołmogorowa) jest wspólny identyfikator, dlatego masz wspólne nazwy.
Ad 2) Myślę, że to po prostu konsekwencja intuicyjnego kierowania się przez ludzi zasadą brzytwy Ockhama.

1
KamilAdam napisał(a):

Ktoś tu pisał już że widzi więcej różnic niż podobieństw i ja się z nim zgadzam. Spójrzmy na Monadę :D

  • Na Wikipedii jest jakiś dziwny tekst o funkcjach unit (która służy do tworzenia monady) i bind (która jest główną funkcjonalnością monady)
  • W Scali jest metoda flatmap zamiast bind. Co do tworzenia bywa różnie, ale jeśli jest tylko jedna metoda tworząca to jest to zwykle apply. Obie nazwy wynikają z lukru składniowego Scali
  • W Haskellu jest funkcja return do tworzenia monady oraz operator >>=, który robi to co funkcja bind

I wtedy wchodzi java - cała na biało:

CompletableFuture

thenAccept
thenAcceptAsync
thenAcceptBoth
thenAcceptBotAsync
thenApply
thenApplyAsync
thenCombine
thenCombineAsync
thenCompose
thenComposeAsync

i jeszcze duzo innych :-)

0

A jak już jesteśmy przy Javie. To w Javie metody fold/reduce, map , forech foreach (map dla void), i filter szczęśliwie nazywają się reduce, map , forech foreach i filter. Ale już w takim groovim to jest inject, collect, each i findAll

1

@Wibowit:

Dziękuję za pokazanie języka @Patryk27. :)

Własny język może stworzyć każdy i kierować się zasadami jakie mu się żywnie podobają.

Zgadzam się, i to w pewnej mierze ogranicza zbiór rozwiązań mojego problemu. Niemniej może również mieć wzorce, ogólnie uznane, w postaci "dobrych praktyk" – którymi może chcieć się kierować.

Dzięki za przypomnienie GraalVM. Zapisałem sobie już dawno temu, by o nim poczytać. :/


@KamilAdam:

W Javie length odnosi się do tablicy a size do kolekcji. Sensu w tym żadnego nie widzę

Masz rację, głupio napisałem. Dla mnie jest różnica między tablicami a napisami, ale chyba tylko taka "wrażeniowa". Nie wiem, co miałoby stanowić między nimi prawdziwą różnicę. Może to, w jaki sposób się je zazwyczaj przetwarza, ja wiem?


@Patryk27:

Idee nie dość, że istniały, to były wysoce nietuzinkowe - otóż nudziło mi się :-P

Ech! Żeby mi się kiedyś tak nudziło, cobym kilka miesięcy z tej nudy przepracował nad jednym projektem i jeszcze wydawał kolejne wersje…

Chciałem się rozwijać, lecz jednocześnie nie miałem pomysłu na żadne użyteczne projekty (…)

Skądś to znam. :)


@Kalrais:

ta brzytwa Ockhama to chyba jeden z dobrych kierunków. Będę musiał jeszcze o niej poczytać w tym kontekście.

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