Jump to content

[Discussion] Named parameters


vicisdev

Recommended Posts

Often times more complex function which do a lot to the user requires a lot of required and optional parameters. Think about InterpolateBetween function.

Is it a best practice to instead of countless parameters passed in to a function to pass in a single table which keys matches those parameters? If not can we turn this into a best practice? A thing such as passing an options table makes the code auto documented so when you look at it you know exaclty what that "false" value means.

Bad way

The code below shows how clueless it can be when you have a lot of parameters to a function. To be honest, it could be even worst if written all in a sigle line.

interpolateBetween(
  0, 0, 0,
  10, 10, 10,
  0.5,
  "Linear"
)

 

Good way

This seems more interesting, doesn't it? You know exactly what all those values means. What do you think?

interpolateBetween({
  from = { 0, 0, 0 },
  to = { 10, 10, 10 },
  progress = 0.5,
  easing = "Linear"
})

 

This also makes it easier to work with optional parameters

Edited by vicisdev
fixing indentation & typos
Link to comment
_interpolateBetween = interpolateBetween

function interpolateBetween(from, to, progress, easing)
  return _interpolateBetween(unpack(from), unpack(to), progress, easing)
end

-- example
interpolateBetween(
  from = { 0, 0, 0 },
  to = { 10, 10, 10 },
  progress = 0.5,
  easing = "Linear"
)

or

_interpolateBetween = interpolateBetween

function interpolateBetween(table)
  return _interpolateBetween(unpack(table.from), unpack(table.to), table.progress, table.easing)
end

-- example
interpolateBetween({
  from = { 0, 0, 0 },
  to = { 10, 10, 10 },
  progress = 0.5,
  easing = "Linear"
})

 

Edited by CastiaL
Link to comment
23 minutes ago, CastiaL said:
_interpolateBetween = interpolateBetween

function interpolateBetween(from, to, progress, easing)
  return _interpolateBetween(unpack(from), unpack(to), progress, easing)
end

-- example
interpolateBetween(
  from = { 0, 0, 0 },
  to = { 10, 10, 10 },
  progress = 0.5,
  easing = "Linear"
)

or

_interpolateBetween = interpolateBetween

function interpolateBetween(table)
  return _interpolateBetween(unpack(table.from), unpack(table.to), table.progress, table.easing)
end

-- example
interpolateBetween({
  from = { 0, 0, 0 },
  to = { 10, 10, 10 },
  progress = 0.5,
  easing = "Linear"
})

 

Ok, I know I could create a workaround to it but this is just a discussion. Also, you wouldn't want to call two unpacks on a function like interpolateBetween which run on every frame.

Your first example is quite interesting and made me search for "Lua named argument". It turns out Lua already have named arguments built in, but it's not how you wrote it. It would be something like this:

local function coolFunction(args)
  -- ...
end

coolFunction { param1 = "val1", param2 = "val2", param3 = "val3" }

I've already used it but I totally forgot about it lol.
Anyway the discussion remains the same.

Edited by vicisdev
Link to comment
  • Moderators
On 12/08/2021 at 19:38, vicisdev said:

You know exactly what all those values means. What do you think?

It does have some benefits. Some very good ones.

But I could also find a few cons, how would you address the following?

1. You have to write more code. (More than double in some cases)

2. You need to know the exact table keys. For some functions those are obvious, for other that might become complicated based on the context and requires more wiki info: x, x1, x2, text, message, speed, velocity, time, duration. This is a language as well as a logic issue. It needs some clear rules in order to function.

3. Somebody has to update the wiki with a 3e syntax.

4. A lot of object instance creation and disposal on onClientRender is a combination I rather not recommend.

Link to comment

This sounds like you do not agree with the Lua language design. The idea of named parameters could be nice if the Lua function call were extended to be a key-value map for parameters in general. Right now the parameters to a function are an integer-map. By adding a new opcode "LUA_CALL_MAPPED" each parameter could first pass the ID and then the value. This would prevent the creation of a table for each function call (IIYAMA made an excellent point why creation of a table would be a bad idea). I disagre with your syntax though, so here is mine:

function named_args map( one, two : two, three : 1 )
    -- one = 1
    -- two = 2
    -- three = 3
end

named_args( "one" = 1, two : 2, 3 )

This syntax is backwards compatible with the old way of calling Lua functions.

Edited by The_GTA
  • Like 1
Link to comment
On 15/08/2021 at 11:19, IIYAMA said:

It does have some benefits. Some very good ones.

But I could also find a few cons, how would you address the following?

1. You have to write more code. (More than double in some cases)

2. You need to know the exact table keys. For some functions those are obvious, for other that might become complicated based on the context and requires more wiki info: x, x1, x2, text, message, speed, velocity, time, duration. This is a language as well as a logic issue. It needs some clear rules in order to function.

3. Somebody has to update the wiki with a 3e syntax.

4. A lot of object instance creation and disposal on onClientRender is a combination I rather not recommend.

I tested 4 and for 10000 iterations on every frame it would increase the frame drawn time by about 4ms (on my PC). I don't know if someone would get a UI with more than 10000 function calls per render, but creating tables does decrese performance. About the third point, I'm not asking to rewrite the MTA API, this practice could be good for later community created libraries. The second point the first sentence I think it's not a problem since you have to know what every parameter means anyway. The first one, I don't fear writing more in order to get better readability. I see a lot of people writing a function call in a single line +100 characters long specially when using DX because they think less lines is better or even naming variables on character long. From the perspective of the interpreter just minify your files and you're good.

 

On 15/08/2021 at 15:59, The_GTA said:

This sounds like you do not agree with the Lua language design. The idea of named parameters could be nice if the Lua function call were extended to be a key-value map for parameters in general. Right now the parameters to a function are an integer-map. By adding a new opcode "LUA_CALL_MAPPED" each parameter could first pass the ID and then the value. This would prevent the creation of a table for each function call (IIYAMA made an excellent point why creation of a table would be a bad idea). I disagre with your syntax though, so here is mine:

function named_args map( one, two : two, three : 1 )
    -- one = 1
    -- two = 2
    -- three = 3
end

named_args( "one" = 1, two : 2, 3 )

This syntax is backwards compatible with the old way of calling Lua functions.

This is very specialized. I'm not a Lua expert, I had no clue about this opcode, I have no idea what's happening here but it's cool. But this opcode would need to be added in the MTA's Lua library, wouldn't it? It's not a configuration you can toggle in your server config files.

Edited by vicisdev
Link to comment
5 hours ago, vicisdev said:

This is very specialized. I'm not a Lua expert, I had no clue about this opcode, I have no idea what's happening here but it's cool. But this opcode would need to be added in the MTA's Lua library, wouldn't it? It's not a configuration you can toggle in your server config files.

Once this opcode is available any resource could enable it inside of their own meta.xml file.

<script src="advanced.lua" type="client" extended_syntax="true" />

We are talking about a possible feature in the future. I could implement it inside of the Lua compiler that I have started working on this month. Then it would be merged into MTA after QA.

Edited by The_GTA
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...