Dla wielu najczystszą formą abstrakcji kodu w obecnej erze programowania binarnego jest „funkcja wyższego rzędu”. Zasadniczo sama funkcja jest traktowana jako dane, a funkcje funkcji są zdefiniowane, tak jak można je zobaczyć w równaniach matematycznych z operatorami określającymi wynik ich operandów oraz z góry ustaloną kolejnością operacji definiujących „zagnieżdżanie” tych operacji. Matematyka ma bardzo mało „rozkazujących nakazów” w swojej strukturze; dwa przykłady, które mogę wymyślić, to: „niech x ma pewną wartość lub może być dowolną wartością zgodną z jakimś ograniczeniem”, oraz „częściowe funkcje”, w których dane wejściowe określają wyrażenie potrzebne do wygenerowania danych wyjściowych. Te konstrukcje są łatwo reprezentowalne jako ich własne funkcje; „funkcja” x zawsze zwraca 1, a „przeciążenie” funkcji definiuje się w kategoriach tego, co jest do nich przekazywane (które w przeciwieństwie do przeciążeń obiektowych można zdefiniować na podstawie wprowadzonych wartości), umożliwiając „częściową” ocenę nazwanej grupy funkcji, nawet pod względem samych siebie. Jako taki, program eliminuje pojęcie imperatywów na niskim poziomie i zamiast tego skupia się na „ocenieniu” danych wejściowych.
Te funkcje wyższego rzędu stanowią kręgosłup „języków funkcjonalnych”; to, co robi program, jest zdefiniowane w kategoriach „czystych funkcji” (jedno lub więcej danych wejściowych, jedno lub więcej danych wyjściowych, brak efektów ubocznych lub „ukryty stan”), które są zagnieżdżone w sobie i oceniane w razie potrzeby. W takich przypadkach większość „imperatywnej logiki” jest wyabstrahowana; środowisko wykonawcze obsługuje faktyczne wywoływanie funkcji i wszelkie warunki, w których jedno lub drugie przeciążenie funkcji może wymagać wywołania. W takim programie kod nie jest uważany za „robienie” czegoś, lecz za „bycie” czymś, a to, co dokładnie jest określane, jest uruchamiane przy początkowym wejściu programu.
Funkcje wyższego rzędu są teraz również podstawą wielu imperatywnych języków; Instrukcje lambda .NET w zasadzie pozwalają na „anonimowy” wkład funkcjonalny w inną „funkcję” (zaimplementowaną imperatywnie, ale teoretycznie nie musi tak być), umożliwiając w ten sposób wysoce konfigurowalne „łączenie” funkcji „ogólnego przeznaczenia” w celu osiągnięcia pożądany wynik.
Inną abstrakcją powszechnie spotykaną w najnowszej rundzie języków programowania jest dynamiczne pisanie zmiennych oparte na koncepcji „pisania kaczego”; jeśli wygląda jak kaczka, pływa jak kaczka, leci jak kaczka i kwakanie jak kaczka, można to nazwać kaczką. Nie ma znaczenia, czy to w rzeczywistości krzyżówka, czy płócienny obraz. Może to znaczenia, czy jest to rzeczywiście gęś lub łabędzia, ale potem znowu może to nie ważne, czy wszystko, co dbają o to, że pływa i muchy, a trochę wygląda jak kaczka. Jest to uważane za ostateczne dziedziczenie obiektu; nie obchodzi cię, co to jest , oprócz nadania mu nazwy; ważniejsze jest to, co robi. W takich językach są w zasadzie tylko dwa typy; „atom”, pojedynczy element informacji (jedna „wartość”; liczba, znak, funkcja, cokolwiek) oraz „krotka” złożona z atomu i „wskaźnika” na wszystko inne w krotce. Nie ma znaczenia, w jaki sposób te typy są implementowane w środowisku binarnym przez środowisko wykonawcze; Używając ich, możesz osiągnąć funkcjonalność praktycznie każdego rodzaju, o jakim możesz pomyśleć, od prostych typów wartości przez ciągi znaków po kolekcje (które, ponieważ wartości mogą być różnych „typów”, pozwalają na „typy złożone”, czyli „obiekty”).