Od 1 listopada 2024 r., wraz z aktualizacją 32.00, stabilizujemy język Verse do wersji 1. Zalecamy aktualizację projektu zarówno ze względu na stabilność, jak i ułatwienie aktualizowania kodu na zasadzie przyrostowego aktualizowania w przypadku pojawienia się w przyszłości aktualizacji języka Verse. Ta aktualizacja jest opcjonalna; bieżąca wersja projektu będzie zawsze kontynuowała pracę na starszej wersji Verse. Mimo tego w przyszłości może dojść do sytuacji, w której konieczne będzie zaktualizowanie projektu do nowszej wersji Verse, jeśli zajdzie potrzeba przesłania jego nowszej iteracji.
Od czasu pierwszej publicznej premiery Verse rozwijaliśmy ten język, wzbogacając go o nowe elementy, a zmiany te były w przejrzysty sposób wprowadzane dla użytkowników bez konieczności aktualizacji języka do nowej wersji. Spodziewamy się kontynuacji tych działań, z dokonywaniem większości zmian języka z zachowaniem wstecznej kompatybilności z poprzednimi wersjami oraz wprowadzaniem ich dla użytkowników wraz z nowymi wersjami UEFN.
Jednak niektóre zmiany językowe nie są kompatybilne wstecznie i mogą wymagać zmian w kodzie w celu jego skompilowania. Takie niezgodne wstecz zmiany zostaną wywołane tylko wtedy, gdy użytkownik zaktualizuje swój projekt do nowej wersji językowej.
W nowszych wersjach języka pojawiają się ostrzeżenia za każdym razem, gdy zapiszesz kod, który nie jest wstecznie zgodny. Na przykład dalsze stosowanie praktyk kodowania, które nie są kompatybilne z nową wersją języka Verse, spowoduje wyświetlenie ostrzeżeń dotyczących kodu.
Jeśli projekt kompiluje się w wersji 0 bez żadnych ostrzeżeń o wycofaniu, możesz zaktualizować do V1 bez żadnych zmian w zachowaniu kodu. Gdy otworzysz w UEFN 32.00 projekt V0, który skompiluje się bez błędów lub ostrzeżeń, edytor wyświetli monit, czy chcesz zaktualizować.
Jeśli z jakiegoś powodu zajdzie u ciebie konieczność przejścia na wyższą lub niższą wersję, możesz to zrobić w ustawieniach projektu.
Click image to enlarge.
Możesz też otwierać pliki projektu z folderu projektów Fortnite i zmieniać wersję Verse pliku .uplugin .
Click image to enlarge.
Większość z tych elementów wycofanych toruje drogę dla przyszłych usprawnień w zakresie języka, natomiast nie zapewnia jeszcze żadnych korzyści dla użytkowników. Dwa wyjątki to kwalifikatory lokalne i porównywanie struktur.
Zmiany w V1
Niepowodzenie polecenia ustaw
Wyrażenie wykonywane przez set nie może już kończyć się niepowodzeniem. Poprzednio kod wyglądał tak:
F():void=
var X:int = 0
set X = FailableExpression[]
Byłoby to dozwolone, a X byłoby ustawione na dowolną wartość oszacowaną w wyniku FailableExpression z ostrzeżeniem. W V1 jest to niedozwolone.
Aby można było naprawić kod, należy upewnić się, że wyrażenie nie może zakończyć się niepowodzeniem. Jednym z możliwych sposobów, aby to zrobić, jest następująca modyfikacja:
var X:int = 0
Value:= FailableExpression[] or DefaultValue
set X = Value
Niepowodzenie w kluczach literału mapy
Wcześniej klucze zapisane w kodzie w mapie mogły kończyć się niepowodzeniem:
map{ExpressionThatCannotFail=>Value}
Prostym przykładem jest map{ (0 = 0) =>0 }, gdzie 0 = 0 zwraca niepowodzenie. Nie jest to już dozwolone.
Mieszanie separatorów średnika/przecinka/znaku nowego wiersza w blokach
Poprzednio mieszanie średników/przecinków/znaków nowego wiersza w oddzielaniu podwyrażeń było dozwolone, w efekcie powstawał kod jak poniżej:
A,
B
for (A := 0..2):
# more code here
Wewnętrzne usunięcie lukru składniowego z kodu, jak pokazano poniżej:
block:
A
B
for (A := 0..2):
# more code here
To oznacza, że obie definicje A w bloku kodu nie wchodziły w konflikt ze sobą nawzajem, ponieważ istniał utworzony niejawny blok, który miał własny oddzielny zakres.
Jest to jednak zachowanie nieprawidłowe i zostało naprawione w najnowszej wersji języka Verse. Teraz ten sam kod traktuje każde podwyrażenie oddzielnie, dając w efekcie:
A
B
for (A := 0..2):
# more code here
Oznacza to, że pierwsze A i druga definicja A := 0..2 przesłaniają się wzajemnie i znaczenie jest niejednoznaczne.
Aby naprawić ten problem, obaj twórcy (i wszyscy, którzy polegają na tym zachowaniu) muszą przestać dodawać średniki/przecinki/znaki nowego wiersza do oddzielania podwyrażeń w całym swoim kodzie Verse.
Example:
PropPosition := Prop.GetTransform().Translation,
if(Round[PropPosition.Z] = Round[ROOT_POSITION.Z]) { break }
Sleep(0.0)
Należy to zmodyfikować w następujący sposób:
PropPosition := Prop.GetTransform().Translation # note the trailing comma here has been removed
if(Round[PropPosition.Z] = Round[ROOT_POSITION.Z]) { break }
Sleep(0.0)
Wcześniej w wersji 28.20 było generowane ostrzeżenie za każdym razem, gdy wykryto jakiekolwiek separatory mieszane. Jest to teraz niedozwolone w najnowszej wersji języka Verse.
Unikatowe zmiany specyfikatorów
Klasy ze specyfikatorem <unique> wymagają teraz efektu konstrukcji <allocates>. Na przykład wyrażenie class<unique><computes> nie jest już dozwolone.
Kwalifikatory wartości lokalnych funkcji
Kwalifikator (local:) można zastosować do identyfikatorów w funkcjach, aby odróżnić je od innych identyfikatorów.
For example:
ExternallyDefinedModuleB<public> := module:
ShadowX<public>:int = 10 # dodawane dopiero po opublikowaniu `ModuleC`
ModuleC := module:
using{ExternallyDefinedModuleB}
FooNoLocal():float=
ShadowX:float = 0.0
ShadowX
Powyższy kod wygeneruje błąd cieniowania, ponieważ ShadowX jest niejednoznaczne (czy pochodzi z ExternallyDefinedModuleB.ShadowX, czy ShadowX w FooNoLocal?).
Aby rozwiązać ten problem, możesz użyć kwalifikatora (local:), by jednoznacznie określić, do którego ShadowX następuje odwołanie, jak w poniższym przykładzie:
ExternallyDefinedModuleA<public> := module:
ShadowX<public>:int = 10 # dodane dopiero po opublikowaniu `ModuleB`
ModuleB := module:
using{ExternallyDefinedModuleA}
FooLocal():float=
(local:)ShadowX:float = 0.0 #W tym miejscu można użyć kwalifikatora `local` do usunięcia dwuznaczności
(local:)ShadowX
Wcześniej było generowane ostrzeżenie, gdy wykryliśmy, że używasz słowa local jako identyfikatora definicji danych, ponieważ jest to teraz zastrzeżone słowo kluczowe. W najnowszej wersji językowej użycie local kończy się błędem, a jeśli chcesz użyć identyfikatora local jako identyfikatora normalnej definicji danych, jego użycie musi być wyraźnie dopuszczone.
Oto inny przykład kwalifikatora lokalnego:
MyModule := module:
X:int = 1
Foo((local:)X:int):int = (MyModule:)X + (local:)X
W tym przykładzie, gdybyśmy nie określili kwalifikatora (local:), X w Foo(X:int), spowodowałby to przesunięcie w cień definicji X:int = 1 bezpośrednio nad nią, ponieważ oba X ` identyfikatory są w tym samym zakresie. W związku z tym użycie kwalifikatora (local:) pozwala nam odróżnić oba te elementy poprzez wyróżnienie X w klauzuli parametrów argumentu Foo jedynie w zakresie Foo. To samo dotyczy również identyfikatorów X w korpusie Foo.
Pola publiczne w strukturach
Wszystkie pola w struct muszą teraz być publiczne. Domyślnie dzieje się tak również w wersji V1. (użycie <public> nie jest już konieczne).
V1 dodaje również możliwość porównywania dwóch struct. Jeśli wszystkie pola struktury są porównywalne, można użyć =, aby porównać dwie instancje struktury na zasadzie pole po polu. Na przykład:
vector3i := struct{X:int, Y:int, Z:int}
vector3i{X:=0, Y:=0, Z:=0} = vector3i{X:=0, Y:=0, Z:=0} # kończy się powodzeniem
vector3i{X:=0, Y:=0, Z:=0} = vector3i{X:=0, Y:=0, Z:=1} # kończy się niepowodzeniem, ponieważ wartość Z jest różna w obu instancjach