Przepraszam za gofrowny tytuł - gdybym mógł wymyślić zwięzły tytuł, nie musiałbym zadawać pytania.
Załóżmy, że mam niezmienny typ listy. Ma operację, Foo(x)
która zwraca nową niezmienną listę z określonym argumentem jako dodatkowy element na końcu. Aby stworzyć listę ciągów znaków z wartościami „Cześć”, „niezmienny”, „świat” możesz napisać:
var empty = new ImmutableList<string>();
var list1 = empty.Foo("Hello");
var list2 = list1.Foo("immutable");
var list3 = list2.Foo("word");
(To jest kod C # i najbardziej interesuje mnie sugestia C #, jeśli uważasz, że język jest ważny. Nie jest to zasadniczo pytanie językowe, ale idiomy języka mogą być ważne.)
Ważne jest to, że istniejące listy nie są zmieniane przez Foo
- więc empty.Count
nadal zwracałby 0.
Innym (bardziej idiomatycznym) sposobem dojścia do wyniku końcowego byłoby:
var list = new ImmutableList<string>().Foo("Hello")
.Foo("immutable")
.Foo("word");
Moje pytanie brzmi: jakie jest najlepsze imię dla Foo?
EDYCJA 3 : Jak ujawnię później, nazwa typu może nie być tak naprawdę ImmutableList<T>
, co wyjaśnia pozycję. Wyobraź sobie, że jest TestSuite
i jest niezmienny, ponieważ cały szkielet, którego jest częścią, jest niezmienny ...
(Koniec edycji 3)
Opcje, które do tej pory wymyśliłem:
Add
: wspólne w .NET, ale oznacza mutację oryginalnej listyCons
: Uważam, że jest to normalna nazwa w językach funkcjonalnych, ale bez znaczenia dla osób bez doświadczenia w takich językachPlus
: jak dotąd mój ulubiony, nie oznacza to dla mnie mutacji . Najwyraźniej jest to również używane w Haskell, ale z nieco innymi oczekiwaniami (programista Haskell może oczekiwać, że doda dwie listy razem zamiast dodawać jedną wartość do drugiej listy).With
: zgodny z niektórymi niezmiennymi konwencjami, ale nie ma w tym samym stopniu „dodatkowości” IMO.And
: niezbyt opisowy.- Przeciążenie operatora dla +: Naprawdę tak bardzo nie lubię; Ogólnie myślę, że operatory powinny być stosowane tylko do typów niższych poziomów. Chcę się jednak przekonać!
Kryteria, których używam do wyboru to:
- Daje prawidłowe wrażenie wyniku wywołania metody (tzn. Że jest to oryginalna lista z dodatkowym elementem)
- Wyjaśnia, jak to możliwe, że nie mutuje istniejącej listy
- Brzmi rozsądnie, gdy są połączone w łańcuch, jak w drugim przykładzie powyżej
Poproś o więcej szczegółów, jeśli nie wyrażę się wystarczająco jasno ...
EDIT 1: Oto moje rozumowanie dla preferując Plus
do Add
. Rozważ te dwa wiersze kodu:
list.Add(foo);
list.Plus(foo);
Moim zdaniem (i jest to sprawa osobista) ta ostatnia jest wyraźnie błędna - przypomina pisanie „x + 5;” jako samodzielne oświadczenie. Pierwszy wiersz wygląda, jakby był w porządku, dopóki nie przypomnisz sobie, że jest niezmienny. W rzeczywistości sposób, w jaki operator plus sam nie mutuje operandów, jest kolejnym powodem, dla którego Plus
jestem moim ulubionym. Bez lekkiej uciążliwości przeciążania operatora wciąż daje to te same konotacje, które obejmują (dla mnie) nie mutowanie operandów (w tym przypadku cel metody).
EDYCJA 2: Powody, dla których nie lubisz Dodaj.
Różne odpowiedzi są skuteczne: „Idź z Add. To właśnie DateTime
działa i String
ma Replace
metody itp., Które nie sprawiają, że niezmienność jest oczywista”. Zgadzam się - tutaj jest pierwszeństwo. Jednak widziałem mnóstwo ludzi zadzwonić DateTime.Add
albo String.Replace
i oczekiwać mutację . Istnieje mnóstwo pytań do grup dyskusyjnych (i prawdopodobnie TAK, jeśli się rozejrzę), na które odpowiada: „Ignorujesz zwracaną wartość String.Replace
; ciągi są niezmienne, zwracany jest nowy ciąg”.
Teraz powinienem ujawnić subtelność pytania - ten typ może nie być listą niezmienną, ale innym niezmiennym typem. W szczególności pracuję nad strukturą testów porównawczych, w której dodajesz testy do pakietu, a to tworzy nowy pakiet. Może być oczywiste, że:
var list = new ImmutableList<string>();
list.Add("foo");
niczego nie osiągnie, ale staje się o wiele bardziej mętny, kiedy zmienisz na:
var suite = new TestSuite<string, int>();
suite.Add(x => x.Length);
Wygląda na to, że powinno być w porządku. Tymczasem dla mnie to wyjaśnia błąd:
var suite = new TestSuite<string, int>();
suite.Plus(x => x.Length);
To po prostu błaga:
var suite = new TestSuite<string, int>().Plus(x => x.Length);
Idealnie chciałbym, aby moi użytkownicy nie musieli być informowani, że zestaw testów jest niezmienny. Chcę, żeby wpadły w pułapkę sukcesu. To może nie być możliwe, ale chciałbym spróbować.
Przepraszam za nadmierne uproszczenie pierwotnego pytania, mówiąc tylko o niezmiennym typie listy. Nie wszystkie kolekcje są tak samoopisowe jak ImmutableList<T>
:)
Odpowiedzi:
W takich sytuacjach zwykle idę z tym
Concat
. Zwykle oznacza to, że tworzony jest nowy obiekt.źródło
Wybrałbym minusy, z jednego prostego powodu: oznacza to dokładnie to, czego chcesz.
Jestem wielkim fanem mówienia dokładnie o co mi chodzi, szczególnie w kodzie źródłowym. Nowicjusz będzie musiał spojrzeć na definicję Wady tylko raz, ale potem przeczyta ją i użyje tysiąc razy. Uważam, że w dłuższej perspektywie przyjemniej jest pracować z systemami, które ułatwiają wspólną sprawę, nawet jeśli koszt początkowy jest nieco wyższy.
Fakt, że byłoby to „bez znaczenia” dla osób bez doświadczenia w FP, jest w rzeczywistości dużą zaletą. Jak zauważyłeś, wszystkie pozostałe słowa, które znalazłeś, mają już jakieś znaczenie, a to znaczenie jest albo nieco inne, albo niejednoznaczne. Nowa koncepcja powinna mieć nowe słowo (lub w tym przypadku starą). Wolałbym, żeby ktoś musiał sprawdzić definicję Wady, niż błędnie założyć, że wie, co robi Add.
Inne operacje zapożyczone z języków funkcjonalnych często zachowują swoje oryginalne nazwy, bez widocznych katastrof. Nie widziałem żadnego nacisku na wymyślenie synonimów „map” i „redukować”, które brzmiałyby lepiej dla osób spoza FP, ani nie widzę w tym żadnej korzyści.
(Pełne ujawnienie: jestem programistą Lisp, więc już wiem, co oznaczają minusy).
źródło
Właściwie to lubię
And
, szczególnie w sposób idiomatyczny. Szczególnie chciałbym, jeśli masz statyczną właściwość tylko do odczytu dla pustej listy i być może ustawisz konstruktor na prywatny, abyś zawsze musiał budować z pustej listy.źródło
Za każdym razem, gdy mam problem z nomenklaturą, natrafiam na interweny.
thesaurus.com zwraca to dla „dodaj”:
Lubię dźwięk
Adjoin
lub prościejJoin
. To właśnie robisz, prawda? Ta metoda może również dotyczyć łączenia się z innymiImmutableList<>
.źródło
Osobiście lubię .With (). Gdybym używał tego obiektu, po przeczytaniu dokumentacji lub komentarzy do kodu, byłoby jasne, co robi, i czyta ok w kodzie źródłowym.
Lub dodajesz „Along”… :)
źródło
Skończyłem z Add dla wszystkich moich niezmiennych kolekcji w BclExtras . Powodem jest to, że jest to łatwa do przewidzenia nazwa. Nie martwię się tak bardzo o ludzi mylących Add z dodawaniem mutującym, ponieważ nazwa typu jest poprzedzona Immutable.
Przez chwilę rozważałem Wady i inne funkcjonalne nazwy stylów. Ostatecznie zdyskontowałem je, ponieważ nie są tak dobrze znane. Na pewno programiści funkcjonalni zrozumieją, ale nie stanowią większości użytkowników.
Inne nazwy: wspomniałeś:
Opcje, które rozważałem:
Niestety tak naprawdę nie wydaje się, że jest to słowo
Staje się to jeszcze bardziej dziwne, gdy weźmie się pod uwagę kolekcje inne niż Lista. Weźmy na przykład Stack. Nawet programiści z pierwszego roku mogą powiedzieć, że stosy mają parę metod Push / Pop. Jeśli utworzysz ImmutableStack i nadasz mu zupełnie inną nazwę, nazwijmy go Foo / Fop, właśnie dodałeś więcej pracy, aby mogli korzystać z Twojej kolekcji.
Edycja: Odpowiedź na edycję Plus
Widzę, gdzie idziesz z Plus. Myślę, że silniejszym przypadkiem byłby minus do usunięcia. Gdybym zobaczył poniższe, z pewnością zastanawiałbym się, co na świecie myślał programista
Największym problemem, jaki mam z Plus / Minus lub nowym parowaniem, jest odczucie przesady. Sama kolekcja ma już wyróżniającą nazwę, niezmienny przedrostek. Po co dalej, dodając słownictwo, którego celem jest dodanie takiego samego rozróżnienia, jak w przypadku przedrostka Immutable.
Widzę argument strony połączenia. Sprawia, że jest wyraźniejszy z punktu widzenia pojedynczego wyrażenia. Ale w kontekście całej funkcji wydaje się to niepotrzebne.
Edytuj 2
Zgadzam się, że ludzie zdecydowanie zostali zdezorientowani przez String.Concat i DateTime.Add. Widziałem kilku bardzo błyskotliwych programistów, którzy dotknęli tego problemu.
Myślę jednak, że ImmutableList to inny argument. Nie ma nic w String ani DateTime, które ustalałyby go jako niezmienny dla programisty. Musisz po prostu wiedzieć , że jest niezmienny przez inne źródło. Tak więc zamieszanie nie jest nieoczekiwane.
ImmutableList nie ma tego problemu, ponieważ nazwa określa jego zachowanie. Można argumentować, że ludzie nie wiedzą, czym jest Niezmienny i myślę, że to również jest ważne. Z pewnością nie wiedziałem o tym aż do około 2 roku na studiach. Ale masz ten sam problem z dowolną nazwą, którą wybierzesz zamiast Dodaj.
Edycja 3: Co z typami takimi jak TestSuite, które są niezmienne, ale nie zawierają słowa?
Myślę, że to prowadzi do pomysłu, że nie powinieneś wymyślać nowych nazw metod. Mianowicie dlatego, że istnieje wyraźna potrzeba uczynienia typów niezmiennymi w celu ułatwienia operacji równoległych. Jeśli skupisz się na zmianie nazw metod dla kolekcji, następnym krokiem będzie mutacja nazw metod na każdym używanym typie, który jest niezmienny.
Myślę, że bardziej wartościowym wysiłkiem byłoby skupienie się na tworzeniu typów identyfikowalnych jako Niezmienne. W ten sposób możesz rozwiązać problem bez ponownego przemyślenia każdego wzoru metody mutacji.
Jak możesz teraz zidentyfikować TestSuite jako Niezmienny? W dzisiejszym środowisku myślę, że jest kilka sposobów
Domyślam się / mam nadzieję, że narzędzia programistyczne zaczną pomagać temu problemowi, ułatwiając identyfikację niezmiennych typów po prostu na podstawie wzroku (inny kolor, mocniejsza czcionka itp.). Myślę jednak, że to jest odpowiedź na zmianę wszystkich nazw metod.
źródło
Myślę, że może to być jedna z tych rzadkich sytuacji, w których dopuszczalne jest przeciążenie
+
operatora. W terminologii matematycznej wiemy, że+
nie dołącza czegoś do końca czegoś innego. Zawsze łączy dwie wartości razem i zwraca nową wartość wynikową.Na przykład intuicyjnie oczywiste jest, że kiedy mówisz
wynikowa wartość x wynosi 4, a nie 22.
Podobnie,
powinien wyjaśnić, co będzie przechowywać każda zmienna. Powinno być jasne, że
list2
nie zmienia się w ostatnim wierszu, ale zamiast tegolist3
przypisywany jest wynik dodawania „słowa” dolist2
.W przeciwnym razie nazwałbym funkcję Plus ().
źródło
[1] + 2 = [1,2]
ale[1] + [2] = [1,[2]]
. Sugerujesz, że zachowanie jest niespójne. Prawdopodobnie dlatego Python nie pozwala na dodanie jednego elementu w ten sposób.Aby być jak najbardziej klarownym, możesz chcieć iść z wordier
CopyAndAdd
lub czymś podobnym.źródło
Nazwałbym to Extend (), a może ExtendWith (), jeśli masz ochotę na gadatliwość.
Rozszerza oznacza dodawanie czegoś do czegoś innego bez zmiany. Myślę, że jest to bardzo istotna terminologia w języku C #, ponieważ jest podobna do koncepcji metod rozszerzenia - „dodają” nową metodę do klasy bez „dotykania” samej klasy.
W przeciwnym razie, jeśli naprawdę chcesz podkreślić, że w ogóle nie modyfikujesz oryginalnego obiektu, użycie jakiegoś przedrostka, takiego jak Get, wydaje mi się nieuniknione.
źródło
Dodano (), dołączono ()
Lubię używać czasu przeszłego do operacji na obiektach niezmiennych. Przedstawia ideę, że nie zmieniasz oryginalnego obiektu i łatwo go rozpoznać, gdy go zobaczysz.
Ponadto, ponieważ nazwy metod mutacji są często czasownikami teraźniejszymi, ma to zastosowanie do większości przypadków, w których natrafisz na niezmienne metody. Na przykład niezmienny stos ma metody „wypychane” i „wyskakujące”.
źródło
Lubię sugestię mmyers dotyczącą CopyAndAdd . Zgodnie z motywem „mutacji”, możesz wybrać Bud (rozmnażanie bezpłciowe), Grow , Replicate lub Evolve ? =)
EDYCJA: Aby kontynuować z moim motywem genetycznym, co powiesz na Procreate , sugerując, że powstaje nowy obiekt, który jest oparty na poprzednim, ale z czymś nowym.
źródło
Jest to prawdopodobnie odcinek, ale w Ruby powszechnie stosuje się oznaczenie rozróżnienia:
add
nie mutuje;add!
mutuje Jeśli jest to wszechobecny problem w twoim projekcie, możesz to zrobić (niekoniecznie za pomocą znaków niealfabetycznych, ale konsekwentnie używając notacji do wskazania metod mutacji / niemutacji).źródło
Join
wydaje się właściwe.źródło
Być może zamieszanie wynika z faktu, że chcesz dwóch operacji w jednym. Dlaczego ich nie rozdzielić? Styl DSL:
Copy
zwróci obiekt pośredni, czyli zmienną kopię oryginalnej listy.With
zwróci nową niezmienną listę.Aktualizacja:
Ale posiadanie pośredniej, zmiennej kolekcji wokół nie jest dobrym podejściem. Obiekt pośredni powinien być zawarty w
Copy
operacji:Teraz
Copy
operacja wymaga delegata, który otrzymuje zmienną listę, aby mógł kontrolować wynik kopiowania. Może zrobić znacznie więcej niż dodawanie elementu, takie jak usuwanie elementów lub sortowanie listy. Można go również użyć wImmutableList
konstruktorze do złożenia początkowej listy bez pośrednich niezmiennych list.Teraz nie ma możliwości błędnej interpretacji przez użytkowników, naturalnie wpadną w pułapkę sukcesu .
Kolejna aktualizacja:
Jeśli nadal nie podoba ci się wzmianka o liście zmiennych, nawet teraz, gdy jest ona zawarta, możesz zaprojektować obiekt specyfikacji, który określi lub skrypt , w jaki sposób operacja kopiowania przekształci jego listę. Użycie będzie takie samo:
Teraz możesz być kreatywny dzięki nazwom reguł i możesz ujawniać tylko funkcje, które chcesz
Copy
obsługiwać, a nie wszystkie możliwościIList
.Na potrzeby łączenia w łańcuch można utworzyć rozsądnego konstruktora (który oczywiście nie będzie używał tworzenia łańcuchów):
Lub użyj tego samego delegata w innym konstruktorze:
Zakłada się, że
rules.Append
metoda zwracathis
.Oto jak wyglądałoby to na twoim najnowszym przykładzie:
źródło
Kilka przypadkowych myśli:
źródło
DateTime w C # używa Add. Dlaczego więc nie użyć tej samej nazwy? Tak długo, jak użytkownicy twojej klasy rozumieją, że klasa jest niezmienna.
źródło
Myślę, że kluczową rzeczą, na którą próbujesz się zdobyć, a która jest trudna do wyrażenia, jest brak zgody, więc może coś ze słowem generatywnym, coś takiego jak CopyWith () lub InstancePlus ().
źródło
Nie sądzę, aby język angielski pozwolił ci sugerować niezmienność w jednoznaczny sposób, używając czasownika, który oznacza to samo, co „Dodaj”. „Plus” prawie to robi, ale ludzie wciąż mogą popełnić błąd.
Jedynym sposobem, aby zapobiec pomyleniu obiektu przez użytkownika z czymś zmiennym, jest podanie go jawnie, albo poprzez nazwę samego obiektu, albo poprzez nazwę metody (jak w przypadku pełnych opcji, takich jak „GetCopyWith” lub „CopyAndAdd”).
Wybierz swój ulubiony „Plus”.
źródło
Po pierwsze, ciekawy punkt wyjścia: http://en.wikipedia.org/wiki/Naming_conventions_(programming) ... W szczególności sprawdź linki „Zobacz także” u dołu.
Jestem zwolennikiem Plus lub And, w równym stopniu skutecznie.
Plus i And są oparte na matematyce w etymologii. Jako takie, oba odnoszą się do operacji matematycznych; oba dają wyrażenie, które w naturalny sposób odczytuje jako wyrażenia, które mogą przekształcić się w wartość, która pasuje do metody o wartości zwracanej.
And
ma dodatkową logiczną konotację, ale oba słowa intuicyjnie odnoszą się do list.Add
oznacza akcję wykonywaną na obiekcie, który jest sprzeczny z niezmienną semantyką metody.Oba są krótkie, co jest szczególnie ważne, biorąc pod uwagę prymitywność operacji. Proste, często wykonywane operacje zasługują na krótsze nazwy.
Wyrażanie niezmiennej semantyki to coś, co wolę robić przez kontekst. Oznacza to, że wolałbym po prostu sugerować, że cały ten blok kodu ma funkcjonalny charakter; zakładamy, że wszystko jest niezmienne. To może być tylko ja. Wolę niezmienność niż regułę; jeśli jest zrobione, robi się dużo w tym samym miejscu; zmienność jest wyjątkiem.
źródło
Co powiesz na Chain () lub Attach ()?
źródło
visualthesaurus.com
(brak powiązania), kiedy szukałemconcatenate
.Wolę Plus (i Minus). Są łatwo zrozumiałe i bezpośrednio odwzorowują operacje obejmujące dobrze znane niezmienne typy (liczby). 2 + 2 nie zmienia wartości 2, zwraca nową, równie niezmienną wartość.
Niektóre inne możliwości:
Splatać()
Zaszczepić()
Narastać()
źródło
Jak o koledze , mateWith lub coitus , dla tych, którzy pozostają. Pod względem rozmnażania ssaki są ogólnie uważane za niezmienne.
Zamierzam też tam wyrzucić Unię . Pożyczone z SQL.
źródło
Najwyraźniej jestem pierwszą osobą Obj-C / Cocoa, która odpowiedziała na to pytanie.
Dzięki temu nie wygrasz żadnych gier w golfa z kodem.
źródło
[object]By[Verb]ing[Object]:
Prefiks +1 metody oznacza, że zostanie zwrócony nowy ciąg, a nie zwykły[verb][Object]:
, co zmutowałoby obiekt w miejscu.Myślę, że „Dodaj” lub „Plus” brzmi dobrze. Nazwa samej listy powinna wystarczyć, aby przekazać niezmienność listy.
źródło
Być może są słowa, które pamiętają mnie bardziej o robieniu kopii i dodawaniu do niej rzeczy zamiast mutowania instancji (np. „Concatenate”). Ale myślę, że warto mieć trochę symetrii tych słów w przypadku innych działań. Nie znam podobnego słowa „usuń”, które myślę o tym samym rodzaju, co „konkatenat”. „Plus” brzmi dla mnie trochę dziwnie. Nie spodziewałbym się, że będzie on używany w kontekście nienumerycznym. Ale to również może pochodzić z mojego nieanglojęzycznego pochodzenia.
Może użyłbym tego schematu
Mają jednak własne problemy, kiedy o tym myślę. Można by pomyśleć, że coś usuwają lub dodają coś do podanego argumentu. Wcale nie jestem tego pewien. Sądzę, że te słowa również nie pasują do tworzenia łańcuchów. Zbyt trudny do pisania.
Może po prostu użyłbym zwykłego „Dodaj” i znajomych. Podoba mi się, jak się go stosuje w matematyce
Cóż, z pewnością 2 pozostaje 2 i dostajesz nowy numer. Chodzi o dwie liczby, a nie o listę i element, ale myślę, że ma pewną analogię. Moim zdaniem
add
niekoniecznie oznacza to, że coś mutujesz. Z pewnością rozumiem, że posiadanie samotnej instrukcji zawierającej tylkoadd
i nieużywanie zwróconego nowego obiektu nie wygląda na błędne. Ale teraz zastanawiałem się nad pomysłem użycia innej nazwy niż „dodaj”, ale po prostu nie mogę wymyślić innej nazwy, nie zmuszając mnie do myślenia „hmm, musiałbym przejrzeć dokumentację, aby wiedzieć, co chodzi o „ponieważ jego nazwa różni się od tego, co miałbym nazywać„ dodać ”. Tylko trochę dziwnych myśli na ten temat z litba, nie jestem pewien, czy to w ogóle ma sens :)źródło
Patrząc na http://thesaurus.reference.com/browse/add i http://thesaurus.reference.com/browse/plus znalazłem zysk i afiks, ale nie jestem pewien, jak bardzo implikują brak mutacji.
źródło
Myślę, że
Plus()
iMinus()
lub, alternatywnieIncluding()
,Excluding()
są uzasadnione w sugerując niezmienne zachowanie.Jednak żaden wybór nazewnictwa nie sprawi, że będzie to całkowicie jasne dla wszystkich, więc osobiście uważam, że dobry komentarz do dokumentu xml przeszedłby tutaj bardzo długą drogę. VS rzuca ci prosto w twarz, kiedy piszesz kod w IDE - trudno je zignorować.
źródło
Append
- ponieważ pamiętaj, że nazwySystem.String
metod sugerują, że mutują one instancję, ale nie robią tego.Lub lubię
AfterAppending
:źródło
list.CopyWith(element)
Podobnie jak Smalltalk :)
A także
list.copyWithout(element)
usuwa wszystkie wystąpienia elementu, co jest najbardziej przydatne, gdy jest używanylist.copyWithout(null)
do usuwania nieuzbrojonych elementów.źródło
Wybrałbym Add, ponieważ widzę zaletę lepszej nazwy, ale problemem byłoby znalezienie różnych nazw dla każdej innej niezmiennej operacji, co może sprawić, że klasa jest dość nieznana, jeśli ma to sens.
źródło