Skocz do zawartości
Vasto_Lorde

[Poradnik] Składnia nowa czy stara? (#pragma newdecls required)

Rekomendowane odpowiedzi

Składnia nowa czy stara?

 

1. Wprowadzenie - Co to w ogóle jest składnia?
W językach programowania, składnia jest to swoista pisemna specyfikacja tego jak dany język ma zostać napisany. W innych słowach, składnia to 'zasady pisowni', które narzucają nam sposób w jaki ma wyglądać napisany przez nas kod, by kompilator zrozumiał co piszemy. Dla każdego języka programowania składnia jest inna.
Do początku roku 2015, Sourcepawn miał tak zwaną starą składnie. Czwartego lutego 2015 został opublikowany SourceMod w wersji 1.7, który zaprezentował nam nową składnię. Sourcepawn jest bardzo starym językiem, dlatego jego developerzy chcieli popchnąć jego rozwój w kierunku innych nowoczesnych i popularnych języków takich jak Java czy C. Z tego powodu nowa składnia bardzo przypomina składnie z tych języków.

 

2. Jakie widoczne zmiany zaszły w składni i wersji 1.7?

I. Deklaracja zmiennych została zmieniona z systemu 'tagów':

Spoiler

new iZmiennaInteger;
new Float:fZmiennaFloat;
new String:sZmiennaString[];

 

Na bardziej formalny (i znajomy z innych języków) system:

Spoiler

int iZmiennaInteger;
float fZmiennaFloat;
char cZmiennaChar[];

 

System tagów (Float: / String:) był przestarzały. Nie dość że w trakcie działania programu można było je zmieniać (co mogło powodować zdziwienie osób patrzących w kod, czemu nagle zmienna zdeklarowana jako Float: przyjmowała wartości String:?), to to, iż oznaczyliśmy zmienną jako Float: wcale nie znaczyło że program postrzega tą zmienną jako typ zmiennoprzecinkowy. Nowa składnia daje nam typy zmiennych z prawdziwego zdarzenia: int, float, char, void.
Typ String: zostaje zamieniony na typ char. Co to za zmiana i czemu jest ważna? Typ char reprezentuje (tak jak wcześniej String: ) znak, lub najczęściej zdeklarowaną tablicę znaków. Poprzedni zapis był bardzo mylący, ponieważ w innych językach typ 'string' jest zupełnie inny niż char. Taka zmiana mocniej wskazuje co dana zmienna char w sobie posiada oraz otwiera drogę developerom na zaimplementowanie prawdziwego typu string w przyszłych wersjach SourceModa.

Ponadto, zmienia się również sposób zapisu funkcji z:

Spoiler

public Action:SpawnPost(new client);
public DoSomething(new param1, new Float: param2);
SetPlayerHP(new client, new health);

 

Na:

Spoiler

public Action SpawnPost(int client);
public void DoSomething(int param1, float param2);
stock void SetPlayerHP(int client, int health);

 

 

II. Możliwa implementacja Metodmap (Methodmaps)
Są to struktury zorientowane obiektowo. Przyczepiają metody do enumów. Może jaśniej będzie, jeśli przedstawię przykład Metodmapy

Spoiler

enum Player
{
	SERVER_PLAYER = 0
}

methodmap Player
{
	public void WyrzucGracza(const char[] wiadomosc)
	{
		KickClient(this.Index, "%s", wiadomosc);
	}
	
	public void ZabijGracza()
	{
		ForcePlayerSuicide(this.Index);
	}
	
	property int Zycie
	{
		public get()
		{
			return GetClientHealth(this.Index);
		}
	}
	
	property bool Zywy
	{
		public get()
		{
			return IsPlayerAlive(this.Index);
		}
	}
	
	property int Index
	{
		public get()
		{
			return int(this);
		}
	}
}

 

Dzięki temu zapisowi, możemy napisać następujący kod:

Spoiler

Player gracz = new Player();

//Jakiś tam kod

CheckPlayer(gracz);

//Jakiś tam kod

void CheckPlayer (Player player)
{
	if (player.Zycie < 0 && player.Zyje)
	{
		player.ZabijGracza();
		
		if (player.Zyje)
		{
			player.WyrzucGracza("Wow, naprawdę masz jakiegoś godmoda, trzeba Cię wyrzucić");
		}
	}
}

 

Zamiast używać zwykłych funkcji na indeksie klienta, Metodmapa daje nam możliwość  napisania działających funkcji na danym obiekcie (w tym przypadku indeksy klienta) i używania ich później w kodzie. Jest to duży krok w stronę obiektowości języka, który poniekąd jest łatwiejszy w użyciu i łatwiej się czyta kod napisany obiektowo. Z drugiej strony, jest trudniejszy w implementacji, najczęściej z tego względu że nauka programowania w szkołach zaczyna się od programowania strukturalnego, nie obiektowego.

 

III. Obiektowo napisane funkcje
W dokumentacji, pliki adt_trie.inc, adt_array.inc oraz menus.inc zostały przepisane na język obiektowy.
Przykład kodu, który można było napisać kiedyś:

Spoiler

new Handle:menu = CreateMenu(Menu_Handler)
AddMenuItem(menu, "de_dust", "Dust")
AddMenuItem(menu, "cs_assault", "Assault")
AddMenuItem(menu, "cs_thunder", "Thunder")
SetMenuExitButton(menu, true)
DisplayMenu(menu, client)

//jakieś działanie kodu
  
//zamknięcie uchwytu menu
CloseHandle(menu);  

 

Przykład kodu który można napisać teraz:

Spoiler

Menu menu = Menu(MenuHandler);
menu.AddItem("de_dust", "Dust");
menu.AddItem("cs_assault", "Assault");
menu.AddItem("cs_thunder", "Thunder");
menu.ExitButton = true;
menu.Display(client);

//Jakieś działanie kodu

//Zwolnienie pamięci gdzie znajduje się menu i usunięcie zmiennej
delete menu;

 

 

3. pragma newdecls required - Jak używać nowej składni w kodzie?
Wystarczy, że gdzieś na początku pliku umieścimy kod:

#pragma newdecls required

Wtedy kompilator będzie od nas wymagał nowej składni i da nam znać przy kompilacji, jeśli coś jest napisane w starej składni.

 

4. To dlaczego używać nowej składni?
Jeśli zależy Ci na schludnym wyglądzie kodu, podążaniem za duchem czasu i nadążanie za nowymi technologiami w dziedzinie IT zawsze dobrze jest zaznajomić się z nowinkami technicznymi. A przejście na nową składnie umożliwia również łatwiejsze poznanie składni innych języków.

 

Bibliografia
Ten tutorial został napisany na podstawie https://www.sourcemod.net/index.php
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami! , https://forums.alliedmods.net/showthread.php?t=244092
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami! , https://wiki.alliedmods.net/SourcePawn_Transitional_Syntax
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami! Z jednego z tych linków skopiowałem również kody programu

 

*Uprasza się o nie kopiowanie poradnika bez wcześniejszego zapytania autora o zgodę

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Co do methodmaps to zauważyłem jak kompilowałem, że 

property int Index
{
	public get()
	{
		return int(this);
	}
}

musi być zdefiniowane na początku, ponieważ kompilator potem nie widzi tego Indexu

error 105: cannot find method or property Player.index
methodmap Player
{
  	property int Index
	{
		public get()
		{
			return int(this);
		}
	}
  
	public void WyrzucGracza(const char[] wiadomosc)
	{
		KickClient(this.Index, "%s", wiadomosc);
	}
	
	public void ZabijGracza()
	{
		ForcePlayerSuicide(this.Index);
	}
	
	property int Zycie
	{
		public get()
		{
			return GetClientHealth(this.Index);
		}
	}
	
	property bool Zywy
	{
		public get()
		{
			return IsPlayerAlive(this.Index);
		}
	}
}

I przy okazji wdarła Ci się literówka bo zamiast KickClient jest KickClent ?

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dołącz do dyskusji

Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.

Gość
Dodaj odpowiedź do tematu...

×   Wklejono zawartość z formatowaniem.   Usuń formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Odnośnik został automatycznie osadzony.   Przywróć wyświetlanie jako odnośnik

×   Przywrócono poprzednią zawartość.   Wyczyść edytor

×   Nie możesz bezpośrednio wkleić obrazków. Dodaj lub załącz obrazki z adresu URL.


×
×
  • Dodaj nową pozycję...