Tomasz Dąbrowski
Programista gier, silników i innych takich dabroz@scythe.pl http://dabroz.scythe.pl @dabrozpl
Dlaczego nie lubię C++?
Złożoność Przestarzały system budowania Pliki nagłówkowe OOP Szablony substandard programmers oraz substandard libraries Debug vs Release Ukrycie problemów wydajnościowych
C? Dobry wybór, ale czasem przydają się dodatkowe możliwości. Okrojony C++? To już mamy. D? Po prawie 15 latach dalej nie słychać 0 większych produkcjach. C#/Java? GC, słaba wydajność. Python/JavaScript/? Ciężko powiedzieć, dalej coś liczą
Dab!
Front-end Lexer Parser gotowe AST Middle-end przetwarzanie AST lowering optymalizacje wysokopoziomowe Back-end mikrooptymalizacje generowanie kodu
int foo = bar(14 + z); INT foo = bar ( 14 + z ) ; ASSIGN VAR foo (int) FUNCALL bar BINOP + CONST 14 VAR z
Front-end Lexer Parser gotowe AST Middle-end przetwarzanie AST lowering optymalizacje wysokopoziomowe Back-end mikrooptymalizacje generowanie kodu FLEX BISON KOMPILATOR (DAB) LLVM
Problemy C++: Co na to Dab?
Język znacznie prostszy od C++ Kompilator może udostępniać bibliotekę do tworzenia AST na podstawie kodu Skutek: mniej problemów z językiem Skutek: łatwe tworzenie narzędzi analizujących/przetwarzających kod
Rezygnacja z zewnętrznych narzędzi Nie potrzeba tworzyć wielu procesów Nie potrzeba operować na plikach! Cała kompilacja może odbywać się w pamięci Skutek: ogromne przyspieszenie kompilacji
Rezygnacja z klasycznych plików nagłówkowych Na podstawie kodu można generować w locie różnego rodzaju nagłówki (np. jako dokumentację) Nie ma znaczenia kolejność typów, zmiennych i funkcji w plikach
Jeżeli już OOP, to z głową Objective-C ma 300% możliwości C++ przy 10% jego złożoności Reflection Docelowo moduł OOP będący połączeniem Lua i Obj-C
Rozwiążmy problemy w inny sposób Typy jako argumenty użyjmy istniejących mechanizmów Raytracing w czasie kompilacji określanie funkcji jako stałych (lepsze constexpr) Kontenery bez konstruktorów i destruktorów można je zrealizować prostszymi środkami Skutek: brak code bloat Skutek: bardziej spójny język Skutek: hashowanie stringów w czasie kompilacji
Prostszy (w tym bardziej ograniczony) język = WIN Mniej okazji do tworzenia koszmarnego kodu Silniejszy (obsługujący systemowo więcej istotnych dla nas problemów) = WIN Mniej powodów do tworzenia koszmarnego kodu
Wybór trybu kompilacji per-funkcja Przełączanie trybów w locie Ręczne sterowanie etapami optymalizacji
Zwracanie uwagi na sprawy nieistotne w większości innych języków Kilka pomysłów: float fun(int* a, int* b) { *a = 2; *b = 4; return *a + *b; warning: pointers a and b may alias warning: Load-Hit-Store in *a warning: expected stall for 42 cycles warning: conversion from int to float in return value }
Problemy i możliwości
C łatwa sprawa DLL no problem Bytecode LLVM jak najbardziej C++ - kiepska sytuacja Pełna obsługa C++ (bo w nagłówkach może być kod) Zarządzanie czasem życia obiektów C++ Pełna obsługa jest nierealna Ale z użyciem Clang można próbować kompilacji do LLVM BC Albo po prostu używać interfejsów C
Podmiana kodu w czasie rzeczywistym Bez ograniczeń edit&continue Także w trybie Release (przy wyłączonym optymalizowaniu funkcji inline) Dzięki JIT można dostarczać optymalny build gry na różne wersje architektury (SSE 4/3 itp.)
float4 jako pełnoprawny typ Komplet operatorów Wbudowany swizzling (float4 ret = color.bgra;) Biblioteka matematyczna (zbliżona do shaderów)
Ideałem byłaby rezygnacja z 32-bitowego kodu w ogóle Niestety 32-bit ma wciąż duży udział w domowych PC Różne architektury które język może obsługiwać dzięki LLVM: ARM (tylko 32-bit), PPC 64-bit musi być standardem, a 32-bit służyć jako fallback Architektura nie jest problemem przy JIT Fat binaries na niektórych OS
No size fits all Poza rdzeniem języka powinny istnieć opcjonalne moduły Przykłady: Język skryptowy Zaawansowany OOP Developerzy powinni mieć możliwość dokładania własnych konstrukcji do języka (choćby w postaci lukru składniowego)
C++ i Lua Dużo kodu potrzebne tylko w celu komunikacji między językami Trudne debugowanie Lua Przy dużych projektach czysto dynamiczny język jak Lua jest kłopotliwy Zamiast tego dodajmy jako opcjonalny element moduł skryptowy
Idea: połączmy Lua i Objective-C Język oparty na prototypach Programowanie obiektowe, ale z możliwością nadpisywania metod per-obiekt Komunikacja z rdzeniem języka za pomocą typu wskaźnikowego (id w Obj-C) Możliwość statycznej (i dynamicznej) kontroli typów id HellSpaceShip = [[SpaceShip alloc] init] HellSpaceShip.Render = { [Base Render]; RenderHellFlames([self Position]) }
LLVM/Clang oferuje analizę statyczną kodu Przykłady zastosowań: Wskaźniki NULL sprawdzanie tylko na najwyższym poziomie wywołań funkcji Wykrywanie literówki nie będących błędami (np. powtórzenie tego samego fragmentu kodu bez zmiany operatora) Przy podjęzyku skryptowym sporo kodu wykonywane jest dynamicznie, ale często można prześledzić wszystkie ścieżki i zredukować wywołania do statycznych
Skoro głównym targetem jest tworzenie gier to pomóżmy w jednym z podstawowych zagadnień Przykładem zaawansowanej integracji z OpenGL może być możliwość instrumentalizacji shaderów (transform feedback + lunarglass) Statyczna analiza potoku OpenGL (redundantne zmiany stanów, niedopasowane formaty wierzchołków itp.)
Trudny temat Są różne opcje: Natywny debugger GDB LLDB Problematyczna obsługa kodu JIT Jednolite debugowanie wszelkiego rodzaju kodu
Status projektu
http://www.dablang.net/ http://github.com/dabroz/dablang Licencja MIT
Pytania?