Funkcja zwraca tylko niezmieniony parametr, bezużyteczne?

15

Właśnie znalazłem tę funkcję w projekcie, nad którym pracuję:

  -- Just returns the text unchanged.
  -- Note: <text> may be nil, function must return nil in that case!
  function Widget:wtr(text)
      return text
  end

Szkoda, że ​​programista nie działa już w firmie. Dlaczego mielibyśmy tworzyć funkcje, które nic nie robią, ale zwracają wywołany parametr?

Czy taka funkcja ma jakieś zastosowanie, nie wymienione w tym przykładzie, ale ogólnie w każdym razie?

Spowodowany

function aFunction(parameter)
    return parameter
end

Kończy się w

aFunction(parameter) == parameter

Dlaczego miałbym pisać coś takiego

aFunction(parameter) == whatIWantToCheck

zamiast

parameter == whatIWantToCheck

?

Sempie
źródło
13
@gnat Jak to, u licha, jest duplikatem?
Kilian Foth,
13
Co? Ta funkcja zwraca swój parametr - tworzenie łańcuchów obejmuje zwracanie this.
Kilian Foth,
11
@gnat Pytanie brzmi, dlaczego ktoś napisałby funkcję, która nic nie robi, tylko zwraca. Tak, możesz zwrócić określone obiekty lub wartości, aby umożliwić tworzenie łańcuchów metod, ale to nie jest jego pytanie. Jego pytanie brzmi: dlaczego ktoś napisałby coś takiego: int getParam(int param) { //DO NOTHING return param; } Z perspektywy łączenia metod jest to całkowicie zbędne i niepotrzebne wywołanie, ponieważ możesz pozostawić funkcję OP poza łańcuchem metod i nie zrobiłoby to żadnej różnicy.
ZeroStatic
4
Jest to prawdopodobnie nie na temat i nie dotyczy lua, ale istnieje w tym przypadku poprawny przypadek użycia w PHP - w starszych wersjach new Foo()->method();nie była poprawna składnia, a function with($what) { return $what; }; with(new Foo())->method();jako obejście zastosowano konstrukcje podobne .
DCoder

Odpowiedzi:

57

Twoje pytanie jest trochę jak pytanie o wartość liczby zerowej, jeśli za każdym razem, gdy dodasz ją do czegoś, otrzymasz tę samą wartość. Funkcja tożsamości jest jak zero dla funkcji. Niby bezużyteczne samo w sobie, ale czasami przydatne jako część wyrażenia wykorzystującego funkcje wyższego rzędu, w którym można przyjąć funkcję jako parametr lub zwrócić ją w wyniku. Dlatego większość funkcjonalnych języków programowania ma idlub identityw swojej standardowej bibliotece.

Innymi słowy, jest to przydatna funkcja domyślna. Tak jak możesz chcieć ustawić offset = 0jako domyślną liczbę całkowitą, nawet jeśli to powoduje, że offset nic nie robi, to może być przydatne, aby móc ustawić filterFunction = identityjako funkcję domyślną, mimo że filtr nic nie robi.

Karl Bielefeldt
źródło
Czy funkcja filtrowania nie powinna zwracać wartości logicznej? W tym przypadku funkcja filtra „zero” byłaby tą, która zwraca true.
Kirill Rakhman
1
@cypressious A zatem funkcja mapy.
sapi
6
Lub trzymać się koncepcji projektowej: wzorzec obiektu
zerowego
@cypressious, to byłoby dla predykatu, który byłby przekazywany jako argument do funkcji filterwyższego rzędu. Funkcja pierwszego rzędu filterma typ [a] -> [a],
Karl Bielefeldt,
Na przykład w C # często używam.OrderBy(x => x)
CodesInChaos
27

Pewnie. Wyobraź sobie zewnętrzny interfejs API, który umożliwia pobieranie rzeczy z absolutnie potrzebnych miejsc, ale musisz określić kryteria filtrowania i formaty wyjściowe dla każdego zapytania, nawet jeśli chcesz uzyskać wszystkie wyniki i uzyskać je dokładnie tak , jak są przechowywane.

Następnie musisz wymyślić trywialną funkcję „akceptuj wszystko” i trywialną funkcję „powrót bez zmian”, aby uzyskać dostęp do danych. wtrjest właśnie takim trywialnym pseudo-formatatorem. Jeśli często używasz tego interfejsu API, może być bardzo przydatne, aby ta funkcja pseudo-pomocnika leżała w pobliżu, zamiast tworzyć anonimową funkcję za każdym razem, gdy o coś zapytasz. (Można rozważyć nazywając ją identityzamiast wtrtak, to od razu jasne, że nic nie robi.)

Kilian Foth
źródło
Tak naprawdę nie zrozumiałem jeszcze sensu, ale taki jest dokładnie scenariusz. Myślę, że po chwili mogę zrozumieć, pracując nad tym projektem, mając na uwadze twoją odpowiedź. atm wydaje mi się to bezużyteczne, ... jeśli dostanę dane rawd, dlaczego miałbym chcieć, aby funkcja ponownie dała mi dane rawdata, ...
Sempie
3
@Sempie Ponownie, jeśli interfejs API wymaga funkcji formatowania, jedynym sposobem na uzyskanie niezmienionego tekstu jest to, że funkcja nic nie robi z tekstem.
Doval
3
Innymi słowy: Jeśli masz funkcję wymagającą przekazania argumentów filtru / formatu i absolutnie nie możesz użyć jej nulljako argumentu, użyj pustej funkcji filtrowania, która filtruje „nic”, aby program przestał narzekać.
ZeroStatic
3
@Sempie Pracowałeś z SQL, prawda? Czy wiesz, jak dołączyć albo nie dołączyć WHEREklauzulę? To luźno kwestia cukru syntaktycznego. Zasadniczo brak WHEREklauzuli jest dokładnie taki sam, jakbyś miał WHEREklauzulę, która po prostu idzie do przodu i zezwala na wszystko. Fakt, że projektanci SQL nie pozwalają określić WHEREklauzuli, zamiast zmuszać ją do odłożenia, nawet gdy akceptuje wszystko, jest mniej więcej składniowym cukrem, i właśnie udostępnili tę opcję dla prostej wygody. ..
Panzercrisis
5
Warto zauważyć, że w wielu przypadkach szybsze i czystsze jest posiadanie kodu bezwarunkowego wywołania metody wirtualnej lub delegata, który może, ale nie musi, zrobić coś pożytecznego, niż kod określający, czy wywołanie jest potrzebne, i pomiń go, jeśli nie.
supercat
15

Czy to nie tylko polimorfizm?

Z mojego doświadczenia z Qt tr() i wtr()metodami należy korzystać (tam, w Qt ) w lokalizacji Widgettekstu.

Więc, wracając tekst niezmieniony ta metoda po prostu mówi: Widget does no localization (translation of the text) by default. Override this function to enable your own logic.

GreenScape
źródło
1
nie zdawałem sobie sprawy, że to kwestia QT - to jest oczywiście odpowiedź.
Corley Brigman
8

Bardzo częstym przypadkiem jest „później dodana funkcjonalność”. Dlatego programista pomyślał, że może nastąpić zmiana tej funkcji później. Ponieważ uzyskujesz do niego dostęp jako funkcję, a nie jako sam parametr, możesz to łatwo globalnie zmienić. Powiedzmy, że masz indeks z:

function getIndex(index)
    return index
end

a ponieważ indeks zaczyna się od 0, wszystko jest w porządku. Później zmienisz komponent gdzieś indziej, ten komponent wymaga przetłumaczenia indeksu, aby zacząć od 1. Trzeba by dodać setki indeksu + 1 wszędzie w kodzie. Ale przy użyciu takiej metody po prostu powiedz:

 function getIndex(index)
    return index+1
end

i wszystko w porządku. Takie funkcje mogą szybko doprowadzić do nadmiernej inżynierii, ale w niektórych momentach mają sens!

reggaemuffin
źródło
2
Tak, choć warto zauważyć, że dokumentowanie funkcji opublikowanej przez OP nie sugeruje, że taki jest cel funkcji w jego przypadku.
Mark Amery
6

Takie funkcje pośredniczące są powszechne w sytuacjach dziedziczenia typu. Klasa podstawowa może nic nie robić, ale klasy pochodne mogą robić różne rzeczy z danymi wejściowymi. Deklaracja funkcji stub w klasie bazowej pozwala wszystkim klasom pochodnym mieć funkcję o tej nazwie, a poszczególne klasy pochodne zastępują ją bardziej skomplikowanym i użytecznym.

jackr
źródło
5

Jeden dodatkowy scenariusz jest podobny do użycia w Pythonie i C # właściwości, ale w językach, które nie mają tej funkcji.

Ogólnie rzecz biorąc, możesz zadeklarować coś jako tylko członka klasy; powiedzmy „nazwa” jako ciąg. Oznacza to, że uzyskujesz do niego dostęp w następujący sposób:

someobject.name

Później decydujesz, że nazwa naprawdę musi zależeć od tego, co znajduje się w obiekcie. To naprawdę powinna być funkcja. Ups! Nawet bez argumentów oznacza to, że cały kod, który ma do niego dostęp, musi zostać zmieniony na

someobject.name()

Ale jeśli masz wiele takich wywołań, szanse na to, że coś pójdzie nie tak, są niewielkie - gdzieś ta zmiana nie zostanie wprowadzona, program się zawiesi, gdy dojdziesz do tego punktu itp.

Właściwości w C # / Python pozwalają zastąpić funkcję tym, co kiedyś było atrybutem, jednocześnie umożliwiając dostęp do niej jak do atrybutu, tj. Bez zmian. Nie musisz nawet planować z wyprzedzeniem.

Jeśli twój język tego nie ma, musisz planować z wyprzedzeniem, ale nadal możesz w pewien sposób wspierać go tak, jak robili to wcześniej ludzie, czyniąc z niego funkcję od samego początku, która nic nie robi. Na początku nie zrobi nic interesującego i wygląda na to, że powinien zostać usunięty, a wiele funkcji tego typu nigdy się nie zmienia. Ale później, jeśli zdasz sobie sprawę, że naprawdę za każdym razem, gdy dzwonisz Widget.wtr, musisz usunąć niektóre znaki specjalne, to nie jest wielka sprawa - to już funkcja, po prostu dodaj ją i gotowe.

TL; DR To może być po prostu mądry programista planujący przyszłe zmiany.

Corley Brigman
źródło
3
Miałoby to sens, gdyby ta metoda zależała od czegokolwiek innego, ale tak nie jest. To nie jest własność, getter / setter ani pole. To metoda, która obecnie nic nie robi. Jedynym sposobem, w jaki planuje przyszłe zmiany, jest zmiana logiki tej metody.
Matthew Steeples
1
Nie musi ... to znaczy, że teraz nie przetwarzam tych danych, ale później, jeśli chcę je przetwarzać, każdy użytkownik tych danych otrzymuje przetwarzane dane za darmo. Głupi przykład: Powiedzmy, że drukujesz ciągi na ekranie i zwykle tak robisz print data. Potem zdajesz sobie sprawę, że wszystkie ciągi muszą być pisane wielkimi literami - musisz znaleźć każdy wydruk w swoim programie i zmienić na print data.upper(). Ale jeśli masz def cdata(data): return datai wszędzie to mówi print cdata(data), to po prostu zmieniasz się na def cdata(data): return data.upper()i to jest jedyna zmiana.
Corley Brigman
Rozumiem, co masz na myśli. To ma sens
Matthew Steeples
2

Nie jest to bezużyteczne, w rzeczywistości może być niezwykle przydatne, ponieważ sprawia, że ​​kod jest bardziej jednolity i elastyczny.

Powiedzmy na przykład, że masz listę osób i listę rozwijaną, z której użytkownik może wybrać, czy chcemy zobaczyć „wszystkich”, czy tylko tych, którzy są „mężczyznami” lub „kobietami”.

Możesz albo traktować „wszystko” jako szczególny przypadek, w którym to przypadku będziesz potrzebować dodatkowego, jeśli i jawnie sprawdzisz ten przypadek, albo możesz mieć funkcję filtrującą, która po prostu zwraca swój parametr (np. Pozwala na przejście wszystkiego), przypisany do użycia w przypadku „wszystkie”.

Hejazzman
źródło
4
To nie pasuje do scenariusza. Miałem na myśli funkcję, która zwraca jego parametry i w żadnym wypadku nie rób nic więcej.
Sempie
@Sempie: Tak właśnie mówi. Jeśli masz Filterklasę lub interfejs z MaleFilteri FemaleFilterpodklasy, a twój kod wymaga jakiegoś filtra, filtr, który nic nie robi (zwraca parametr bez zmian), jest tym, jak sobie radzisz All. Funkcja nigdy nic nie robi, ale można ją zastąpić tą, która robi.
Mag
@Magus, ale w twoim scenariuszu funkcja jest pewnego rodzaju symbolem zastępczym, który albo zostanie zastąpiony później, albo po prostu istnieje, ponieważ stara funkcja stała się przestarzała, ale program potrzebuje tego przejścia. W każdym razie to nie jest przekazanie. Funkcja nie przekazuje niezmienionego parametru innej funkcji, jak mógłby to zrobić filtr, ale zwraca ją do funkcji wywołującej.
Sempie
@Sempie Nie, nie jest to ani trucizna, ani tymczasowe przejście. Jest to użyteczne pojęcie kodowania (i matematyki), funkcja „tożsamości”. I tak, nadal jest to przekazywanie, niezależnie od tego, czy zwraca ono „inną funkcję”, czy funkcję wywołującą. Kluczem jest to, że funkcja „tożsamości” może być jedną z wielu możliwych funkcji wywoływanych przez funkcję wywołującą i jest używana pozwala uniknąć specjalnego i specjalnego, gdy wywoływana funkcja nie musi nic robić.
Hejazzman