Czym jest ICI i dlaczego warto go poznać
ICI to język interpretowany stworzony w Australii, który łączy prostotę skryptową z zaskakująco bogatym systemem typów. Nazwa nie jest akronimem — to po prostu “ICI”, krótkie i łatwe do wpisania. Język został zaprojektowany jako narzędzie do szybkiego prototypowania i automatyzacji, z naciskiem na elastyczność i wygodę programisty. Choć nigdy nie zdobył globalnej popularności, ICI ma kilka unikalnych rozwiązań, które zasługują na uwagę.
ICI jest językiem proceduralnym z dynamicznym typowaniem i bogatym zestawem wbudowanych struktur danych. Obsługuje tablice, zbiory (sets), struktury (odpowiednik słowników/map), stringi i liczby — wszystko jako typy pierwszej klasy z operacjami dostosowanymi do każdego z nich. Składnia jest zbliżona do C, co czyni ją znajomą dla większości programistów.
Dlaczego warto go poznać? Bo ICI to fascynujący przykład języka, który próbował rozwiązać realne problemy programistów w sposób, który wyprzedzał swoje czasy. Jego system typów z operacjami na zbiorach i strukturach był elegancki i praktyczny. Nawet jeśli nie będziesz pisać w ICI produkcyjnego kodu, jego idee są warte poznania.
Krótka historia i ewolucja
ICI został stworzony przez Tima Longa w latach 80. w Telecom Australia (obecnie Telstra). Long potrzebował języka skryptowego, który byłby bardziej ekspresyjny niż shell, ale prostszy niż C. ICI miał wypełnić lukę między niskopoziomowym programowaniem systemowym a wysokopoziomowym skryptowaniem.
Język ewoluował przez lata 90., zyskując bogatszy system typów, wsparcie dla modułów i rozbudowaną bibliotekę standardową. ICI 5, ostatnia główna wersja, była dostępna jako open source i działała na Unix, Windows i innych platformach. Projekt był aktywnie rozwijany do wczesnych lat 2000., po czym aktywność społeczności stopniowo zamierała.
Mimo że ICI nie zdobył szerokiej popularności, był ceniony przez swoich użytkowników za pragmatyzm i elegancję. Tim Long projektował język z perspektywy praktyka — kogoś, kto musiał rozwiązywać realne problemy systemowe, a nie teoretyka szukającego akademickiej perfekcji. To podejście widać w każdej decyzji projektowej.
Kluczowe cechy i filozofia
ICI wyróżnia się bogatym systemem typów jak na język skryptowy. Oprócz standardowych liczb i stringów, ICI ma natywne wsparcie dla zbiorów (sets) z pełnym zestawem operacji: union, intersection, difference. Ma też struktury — odpowiednik słowników — które mogą być używane jako obiekty z dziedziczeniem przez prototypy. Tablice są dynamiczne i heterogeniczne.
Składnia ICI jest celowo bliska C. Nawiasy klamrowe, średniki, operatory ==, !=, &&, || — wszystko jest znajome. To była świadoma decyzja: Long chciał, żeby programiści C/C++ czuli się w ICI jak w domu. Ale pod znajomą powierzchnią kryją się mechanizmy, których C nie ma: garbage collection, closures, operacje na zbiorach i elastyczne struktury danych.
Filozofia ICI to “język klejowy z mocą”. Z jednej strony ICI potrafi wywoływać funkcje C, pracować z plikami, zarządzać procesami i komunikować się przez sieć — typowe zadania języka skryptowego. Z drugiej strony ma wystarczająco bogaty system typów i operacji, żeby nie musieć uciekać do C przy każdej poważniejszej operacji na danych.
Ciekawą cechą jest traktowanie struktur jako obiektów. Struktura w ICI może mieć “superstrukturę” — odpowiednik prototypu w JavaScript. Kiedy odwołujesz się do klucza, którego nie ma w strukturze, ICI automatycznie szuka go w superstrukturze. To prosty, ale skuteczny mechanizm dziedziczenia, który nie wymaga klas ani hierarchii.
Gdzie ICI sprawdza się najlepiej
ICI był pierwotnie używany w Telecom Australia do automatyzacji zadań systemowych, przetwarzania danych i prototypowania. Administratorzy systemów używali go do skryptów, które były zbyt złożone dla shella, ale nie wymagały pełnego programu w C. Przetwarzanie logów, generowanie raportów, zarządzanie konfiguracją — to były codzienne zadania ICI.
Drugim obszarem było prototypowanie algorytmów i systemów. Dzięki bogatym strukturom danych i szybkiemu cyklowi edit-run, ICI pozwalał szybko testować pomysły przed implementacją w C lub C++. Niektóre zespoły używały ICI jako języka konfiguracyjnego i skryptowego dla większych systemów.
Dziś ICI jest głównie ciekawostką historyczną i przedmiotem zainteresowania entuzjastów niszowych języków programowania. Ale jego podejście do struktur danych i prototypowego dziedziczenia pozostaje inspirujące dla projektantów nowych języków.
Jak wygląda kod w ICI
Prosty program z operacjami na strukturach:
/* Definicja prototypu osoby */
osoba = [set
nazwa = "",
wiek = 0,
przedstaw_sie = function() {
printf("Czesc, jestem %s i mam %d lat.n", this.nazwa, this.wiek);
}
];
/* Tworzenie instancji */
jan = [set osoba | nazwa = "Jan", wiek = 30];
anna = [set osoba | nazwa = "Anna", wiek = 25];
jan.przedstaw_sie();
anna.przedstaw_sie();
[set ...] tworzy strukturę, | oznacza dziedziczenie z prototypu. this odnosi się do bieżącego obiektu. Proste i eleganckie.
Operacje na zbiorach:
a = [set 1, 2, 3, 4, 5];
b = [set 3, 4, 5, 6, 7];
union = a | b;
intersection = a & b;
difference = a - b;
printf("Suma: %sn", union);
printf("Czesc wspolna: %sn", intersection);
printf("Roznica: %sn", difference);
Operatory |, &, - na zbiorach to naturalna notacja matematyczna. ICI traktuje zbiory jako typ pierwszej klasy z dedykowanymi operatorami.
Ekosystem i narzędzia
Ekosystem ICI jest dziś minimalny. Interpreter jest dostępny jako open source i można go skompilować na większości platform uniksowych. Dokumentacja jest kompletna, choć nie aktualizowana od lat. Nie ma dedykowanego IDE — programiści ICI używali zwykłych edytorów tekstu z podświetlaniem składni.
Biblioteka standardowa ICI zawiera moduły do pracy z plikami, procesami, siecią, wyrażeniami regularnymi i matematyką. Istnieje też interfejs FFI (Foreign Function Interface) do wywoływania funkcji C bezpośrednio z ICI, co było kluczowe dla jego roli jako języka klejowego.
Społeczność ICI nigdy nie była duża i dziś jest praktycznie nieaktywna. Strona projektu i repozytoria istnieją w archiwach, ale nowe treści nie powstają. ICI to język, który można poznać z dokumentacji i kodu źródłowego, ale nie ma już aktywnego wsparcia społeczności.
Mocne i słabe strony
Największą zaletą ICI jest pragmatyczny design. Język łączy znajomą składnię C z bogatymi strukturami danych i garbage collection. Operacje na zbiorach jako typach pierwszej klasy to rzadkość w językach skryptowych. Prototypowe dziedziczenie przez struktury jest proste i skuteczne. ICI był “wystarczająco dobry” do większości zadań systemowych i prototypowych.
Kolejną zaletą była wydajność jak na interpreter. ICI był zoptymalizowany pod kątem typowych zadań skryptowych i radził sobie dobrze z przetwarzaniem tekstu i danych. Interfejs do C pozwalał na wydajnościowe escape hatch, gdy interpreter był za wolny.
Największą wadą jest brak społeczności i ekosystemu. ICI nigdy nie zdobył critical mass użytkowników, co oznacza brak bibliotek, tutoriali, odpowiedzi na Stack Overflow czy wsparcia. Dziś nauka ICI to samotna przygoda z dokumentacją.
Kolejnym problemem jest brak nowoczesnych funkcji. ICI nie ma async/await, pakietów, modułów w nowoczesnym sensie, ani wsparcia dla współczesnych paradygmatów jak reactive programming. Język zatrzymał się w czasie i nie nadąża za ewolucją potrzeb programistów.
Podsumowanie
ICI to zapomniany klej systemowy, który zasługuje na wspomnienie. Jego podejście do struktur danych, prototypowego dziedziczenia i operacji na zbiorach było eleganckie i wyprzedzało swoje czasy. Jeśli interesujesz się historią języków programowania i szukasz inspiracji w nieoczywistych miejscach, ICI jest wart kilku godzin eksploracji.
Przyszłość ICI jako aktywnego języka jest niestety przeszłością. Projekt nie jest rozwijany, społeczność nie istnieje, a nowsze języki skryptowe (Python, Lua, Ruby) dawno zajęły niszę, którą ICI próbował wypełnić. Ale idee ICI — bogate typy danych w języku skryptowym, prototypowe dziedziczenie, operacje na zbiorach — żyją dalej w innych językach.

