sourcepawn icon indicating copy to clipboard operation
sourcepawn copied to clipboard

typedef'ing extended to identifiers/variables

Open kevyonan opened this issue 8 years ago • 5 comments

'ello m8s, I would like to put an official request for typedefing to extend to variables. I know that using "enum" with a name can technically do this by implicitly typedefing int to the enum's name but I'd like the option to typedef other names as well as arrays of these types.

EDIT: I've edited the examples to fit the grammar of 'typedef' which is typedef ::= "typedef" symbol "=" full-type-expr term

I'll just code in my examples

#include <sourcemod>

// makes declaring vec3 an array of float.
typedef vec3_t = float[3];
...
// is really 'float origin[3];'
vec3_t origin;

// this would be an error, functions can only return 'type[]'
vec3_t GetOrigin()
{
	return origin;
}
void SetOrigin(vec3_t origin)
{
	SetEntPropFloat(1, Prop_Send, "m_flOrigin", origin);
}

or another example case with strings

typedef StrNameBuffer_t = char[64];

// "char name[64];"
StrNameBuffer_t name;
strcopy(name, sizeof(name), "example typedef");

more complex example

typedef PlayerFields_t = StringMap;
...
PlayerFields_t fields;
fields = new PlayerFields_t();
methodmap Player {
	public Player() {
	}
	property int iEquipment
	{
		public get() {
			int i; fields.GetValue("iEquipment", i);
			return i;
		}
		public set(const int val) {
			fields.SetValue("iEquipment", val);
		}
	}
};
// player methodmap is defined, we can typedef it now
typedef Enemy_t, Friendly_t = Player;

another, more 'out of the wild' example

typedef color_t = int[4];
color_t color={ 255,255,255,255 };
SetEntityRenderColor(client, color[0], color[1], color[2], color[3]);

Faster method of creating convars!

enum {
    ...
    VersionNum
};
typedef Convars_t = ConVars[VersionNum+1];
Convars_t PluginConvars;

more practical example from an existing plugin called "projectile detector". Original code.

stock void GetProjPosToScreen ( const int client, const float vecDelta[3], float& xpos, float& ypos )
{
	float playerAngles[3]; GetClientEyeAngles(client, playerAngles);

	float vecforward[3], right[3], up[3] = { 0.0, 0.0, 1.0 };
	GetAngleVectors(playerAngles, vecforward, nullvec, nullvec );
	vecforward[2] = 0.0;

	NormalizeVector(vecforward, vecforward);
	GetVectorCrossProduct(up, vecforward, right);

	float front = GetVectorDotProduct(vecDelta, vecforward);
	float side = GetVectorDotProduct(vecDelta, right);

	xpos = 360.0 * -front;
	ypos = 360.0 * -side;

	float flRotation = (ArcTangent2(xpos, ypos) + FLOAT_PI) * (57.29577951);

	float yawRadians = -flRotation * 0.017453293; //FLOAT_PI / 180.0; // Convert back to radians
	// Rotate it around the circle
	xpos = ( 500 + (360.0 * Cosine(yawRadians)) ) / 1000.0; // divide by 1000 to make it fit with HudTextParams
	ypos = ( 500 - (360.0 * Sine(yawRadians)) ) / 1000.0;
}

code using typedef

typedef vec3_t = float[3];
stock void GetProjPosToScreen ( const int client, const vec3_t vecDelta, float &xpos, float &ypos )
{
	vec3_t playerAngles;
        GetClientEyeAngles(client, playerAngles);

	vec3_t vecforward, right, up = { 0.0, 0.0, 1.0 };
	GetAngleVectors(playerAngles, vecforward, NULL_VECTOR, NULL_VECTOR );
	vecforward[2] = 0.0;

	NormalizeVector(vecforward, vecforward);
	GetVectorCrossProduct(up, vecforward, right);

	float front = GetVectorDotProduct(vecDelta, vecforward);
	float side = GetVectorDotProduct(vecDelta, right);

	xpos = 360.0 * -front;
	ypos = 360.0 * -side;

	float flRotation = (ArcTangent2(xpos, ypos) + FLOAT_PI) * (57.29577951);
	float yawRadians = -flRotation * 0.017453293;

	// Rotate it around the circle
        // divide by 1000 to make it fit with HudTextParams
	xpos = ( 500 + (360.0 * Cosine(yawRadians)) ) / 1000.0;
	ypos = ( 500 - (360.0 * Sine(yawRadians)) ) / 1000.0;
}

kevyonan avatar Jun 07 '17 04:06 kevyonan

Ooh, yes please, this looks and sounds extremely useful.

TF2CutContentWiki avatar Jun 12 '17 21:06 TF2CutContentWiki

changed the request to better fit the current grammar of typedef

kevyonan avatar Jun 14 '17 17:06 kevyonan

While I agree that typedef'ing is really nice for languages with complex types, SourcePawn does not have many types, so I think it would just result in everyone calling their types whatever they like, and other people being confused when trying to read their code.

Also, your "complex" example is already possible with methodmap inheritance:

methodmap PlayerFields < StringMap
{
	property int iEquipment
	{
		public get() {
			int i; this.GetValue("iEquipment", i);
			return i;
		}
		public set(const int val) {
			this.SetValue("iEquipment", val);
		}
	}
}

ErikMinekus avatar Jun 24 '17 08:06 ErikMinekus

you seem to misinterpret the purpose of typedef, Typedef exists to give meaning to the datatype you're using.

having typedef StrNameBuffer_t = char[64]; gives a very clear meaning and purpose as to what StrNameBuffer_t is for and why.

The kind of coder who uses typedef to name variables whatever they like is the kind of coder who clearly doesn't want maintainable code. My request for typedef still stands as such an argument as a consequence is flawed.

Secondly, it would give a major advantage in use with arrays.

the benefits of typedef in sourcepawn heavily outweigh the drawbacks.

kevyonan avatar Jun 26 '17 07:06 kevyonan

This is something I'd really like to do, and the experimental v2 frontend does support it. This sort of thing used to be impossible in spcomp, but nowadays it's more like a 7 out of 10 in difficulty. Any kind of declaration goes through a unified sub-parser, and we could have that parser detect typedefs and unwrap them. The rest of the compiler would never have to know that typedefs exist.

Constructs that use tags and types outside of declarations would need special support. view_as<> and return values are good examples. We'd also need to specify that typedefs are ordered (i.e. no use-before-define), that they are not recursive, and handle compound cases like:

typedef vec3 = float[3];
typedef matrix3x2 = vec3[2];
matrix3x2 matrices[10];

dvander avatar Jun 26 '17 08:06 dvander