4

I have a configuration script where the user can enter values either as an absolute value or a percentage value.

Absolute values are written as a value between 0.0 and 1.0 while percentage value are written as 0 to 100.

How can I distinguish 1 from 1.0? If I were to use strings, then it's not a problem for sure... I would like to keep this configuration simple and not have to rely strings.

Is this possible at all?

RECAP:

a = 1
b = 1.0

How to tell that a is not of the same type as b.

EDIT The configuration file look something like this:

local config = {}

-- A lot of comments describing how to configure

config.paramA = 1
config.paramB = 1.0

return config

In my processing script i read the configs like this:

config = require 'MyConfigFile'

config.paramA
config.paramB
Max Kielland
  • 5,627
  • 9
  • 60
  • 95
  • How are you reading the file? Can you just use the string value before converting to numbers for normal usage? And then "tag" the value somehow? – Etan Reisner Sep 08 '15 at 14:11
  • possible duplicate: http://stackoverflow.com/questions/726958/query-lua-userdata-type-from-c – jean Sep 08 '15 at 14:17
  • @jean no this is not userdata accessed from C/C++ I need to do this in Lua script on a number Lua type. – Max Kielland Sep 08 '15 at 14:28
  • 2
    What if the user wants to write in a percentage value with a decimal in it, like 12.5? Have you considered allowing only absolute values or only percentages?You said your goal is simplicity and IMHO having 1 and 1.0 mean different things is very confusing. – hugomg Sep 08 '15 at 14:43
  • If it was a string this wouldn't be a problem at all, I just wanted to know if it was possible without strings. As @Youka mentioned, it is possible in Lua 5.3. – Max Kielland Sep 08 '15 at 15:30

4 Answers4

7

With Lua 5.3 came the integer data type which allows to differ between integer & floating point numbers and provides better performance in some cases. math.type is the function to get the subtype of a number.

local x = 1.0
print(math.type(x)) -- float
x = 1
print(math.type(x)) -- integer

If your percent value should be floating point too, William already called it: "a number is a number". You have to add an additional information to your number to differentiate, like packing it in a table with an identifier. Because you have just 2 cases, a boolean would be a cheap solution.

Youka
  • 2,646
  • 21
  • 33
  • This is indeed an interesting solution, but i forgot to add the tag Lua 5.2. I have no control over the Lua version used :( – Max Kielland Sep 08 '15 at 15:26
  • I marked this as the solution because it is possible, in Lua 5.3 at least. However, for my own problem I can't use this solution. I have to fallback on my plan B to use strings instead. – Max Kielland Sep 08 '15 at 15:39
  • @MaxKielland If you care about performance, doing a string->number conversion isn't a very smart solution. In case of your Lua interpreter is [luajit](http://luajit.org/) a table may even be optimized to something cheaper than your string solution. – Youka Sep 08 '15 at 15:53
4

From PIL you can see that a number is a number and therefore there's no way to distinguish 1 from 1.0 when working with them because they do have the same type

A way to to solve your problem is using a table that contains both the value and the type:

config.paramA = { 1, 'i' }
config.paramB = { 1.0, 'd' }

Or using a string and parsing it before converting to an integer:

config.paramA = '1'
config.paramB = '1.0'
William Barbosa
  • 4,936
  • 2
  • 19
  • 37
  • As I already said, if it was a string there wouldn't be a problem at all ;) The table thing is an interesting solution but it makes it more complicated. Then a string with just '100%' or '1' would be much easier for the user. – Max Kielland Sep 08 '15 at 15:28
2

With Lua 5.1 and 5.2 there is no difference, which can be seen from luac output (luac -i) as local a, b = 1, 1.0 generates the following code:

main <1.lua:0,0> (3 instructions, 12 bytes at 007D04E8)
0+ params, 2 slots, 0 upvalues, 2 locals, 1 constant, 0 functions
    1   [1] LOADK       0 -1    ; 1
    2   [1] LOADK       1 -1    ; 1
    3   [1] RETURN      0 1

Lua 5.3 allows to distinguish between the two using math.type as they have different subtypes.

As a solution to your particular problem, if you really want to make it a non-integer, you can probably add a very small delta to the number: 1.0000001 instead of 1.0.

Paul Kulchenko
  • 25,884
  • 3
  • 38
  • 56
  • This is also an interesting solution, but it complicates it for the user to understand why they have to add so many decimals. I think I will use my next backup plan to use a String with a % sign instead. – Max Kielland Sep 08 '15 at 15:34
1

some suggestions:

1) allow only one of the two formats

2) use a function to make the format explicit

config.paramA = percent(1.9)
config.paramB = portion(1)

those functions could create tables with type info or just convert the value to a consistent type

ryanpattison
  • 6,151
  • 1
  • 21
  • 28
  • I like this idea too :) it is clean and simple to understand. – Max Kielland Sep 08 '15 at 15:35
  • 2
    Another suggestion: use different keys. E.g. `config.paramA = 1` vs. `config.paramA_percent = 1`. Using some metatable tricks both can write to the same field. – siffiejoe Sep 08 '15 at 15:50