[Home] [Downloads] [Search] [Help/forum]

Gammon Software Solutions forum

See www.mushclient.com/spam for dealing with forum spam. Please read the MUSHclient FAQ!

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Lua
. . -> [Subject]  Comparing a function to another

Home  |  Users  |  Search  |  FAQ
Username:
Register forum user name
Password:
Forgotten password?
(New message)
Subject: Comparing a function to another
Name:
Your forum user name.
Register forum user name
Password:
Your forum password.
Forgotten password?
Message:
Message to be posted (in English, please)
Maximum of 6000 characters. Text only please, no HTML.
Forum codes:
Check this if your message uses 'forum codes' or templates (auto-detected for new posts).
Forum codes Templates

Save this message ...


Subject review (reverse sequence)

Pages: 1 2  

Posted by Twisol   USA  (2,229 posts)  [Biography] bio
Date Mon 26 Apr 2010 07:35 PM (UTC)  quote  ]
Message
David Haley said:


prompt_funcs = {}
names = {'affliction', 'bla', 'foo'}

for _, name in ipairs(names) do
  -- val is nil here and in your code, by the way
  local val = nil
  prompt_funcs[name] = function () affs:add (name, val) end
end


Now, for a given name, you have a unique function that adds that name.

In other words, to give functions unique handles, you don't need to spell every one out implicitly; you can generate the functions.


That's also the approach ACS2 (which I pointed out before) takes for generating its affliction-handler functions. :)

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by David Haley   USA  (3,881 posts)  [Biography] bio   Moderator
Date Mon 26 Apr 2010 06:24 PM (UTC)  quote  ]

Amended on Mon 26 Apr 2010 07:42 PM (UTC) by David Haley

Message
I don't really understand what forces you to do it this way or even why it's more convenient. Maybe there's something I'm not seeing based on what you have or haven't said about your problem description, but this setup just seems weird and convoluted to me.

If I'm understanding you correctly, your problem is that you want a generic way of adding functions to your prompt queue, and don't want to list out 100 functions that are all the same.

That's ok: you can still give them names or at least handles, if you create a map from name to function:


prompt_funcs = {}
names = {'affliction', 'bla', 'foo'}

for _, name in ipairs(names) do
  -- val is nil here and in your code, by the way
  local val = nil
  prompt_funcs[name] = function () affs:add (name, val) end
end


Now, for a given name, you have a unique function that adds that name.

In other words, to give functions unique handles, you don't need to spell every one out explicitly; you can generate the functions.

I suppose it's kind of ok to create an identifier as you ad things into the queue, but that's unsafe and kind of weird.

(EDIT: fixed implicitly --> explicitly)

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
[Go to top] top

Posted by Ksajal   (17 posts)  [Biography] bio
Date Mon 26 Apr 2010 05:29 PM (UTC)  quote  ]

Amended on Mon 26 Apr 2010 05:39 PM (UTC) by Ksajal

Message
David Haley said:

My suggestion works with more than just names, but it does seem like your functions are complex enough to not be just data. But then the question is why exactly can't you give these functions proper names or at least values that you can directly compare?

Because for each module that may queue a function I have a method that does that automatically, without me directly specifying the function. I'm not a programmer, I do it just for fun, I find it difficult to find the right words (I'm not even a native English speaker, just take a look at the typo in the thread title), and my code may seem really weird at times, but that's how I imagined it working, so here is an example.

Most of the time, I queue the function affs:add (name, val) in my prompt. So instead of typing each time prompt:queue (function () affs:add ("affliction")end, "affs_add_affliction", true) I use this:

function affs:add_queue (name, val)

prompt:queue (function () affs:add (name, val)end, "affs_add_"..name, true)

end--function

affs:add_queue ("affliction")


It's just easier to type, and modify. Instead of modifying each different function, I just modify the affs:add_queue (name, val). The same reason I use affs:add (name, val) instead of affs ["current"] [aff] = val
[Go to top] top

Posted by David Haley   USA  (3,881 posts)  [Biography] bio   Moderator
Date Mon 26 Apr 2010 02:36 PM (UTC)  quote  ]
Message
My suggestion works with more than just names, but it does seem like your functions are complex enough to not be just data. But then the question is why exactly can't you give these functions proper names or at least values that you can directly compare?

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
[Go to top] top

Posted by Ksajal   (17 posts)  [Biography] bio
Date Mon 26 Apr 2010 02:18 PM (UTC)  quote  ]

Amended on Mon 26 Apr 2010 02:36 PM (UTC) by Ksajal

Message
Example of uses:

--the function
function prompt:queue (f, unique_id, if_I_remove_it_in_case_of_illusion)

for k, v in ipairs (self ["queued"] do
if v==id then
return
end --if
end --for

self ["queued"] [#self ["queued']] = id
self ["ids"] [id] = f

if if_I_remove_it_in_case_of_illusion then
self ["check"] [id] = true
end --if

end--function

--uses
prompt:queue (function () system:cured_asleep ()end, "cured_asleep", "remove_it_if_illusion")

--or

prompt:queue (function () system:cured_asleep flags:add_check ("recklessness") ()end, "some_unique_id", true)

--or

prompt:queue (function ()
  system:cured ("slitthroat")
  if bals:get ("elixir")==0.5 and not string.find (flags:get ("applying_salve") or "nil", "health") then fst:elixir () end
  if bals:get ("purg")==0.5 then fst:purg ()end
  if bals:get ("herb")==0.5 then fst:herb ()end
  end, "another_unique_id", true)

--or

prompt:queue (function () defs:lostdef (defense) end, "defs_lostdef_defense", true)

I'm not only storing affliction names.
[Go to top] top

Posted by David Haley   USA  (3,881 posts)  [Biography] bio   Moderator
Date Mon 26 Apr 2010 02:01 PM (UTC)  quote  ]
Message
All of your operations appear to be data-driven, meaning that you can define the operation based on the data it operates on, and you are not forced to define it as the functional operation itself.

It's unclear to me why (or even if) you need to queue whole functions and not the data they're operating on. For example, why this:

prompt:queue (function () affs:add ("paralysis") end, "affs_add_paralysis", "delete_it_if_illusion")

and not this:
prompt:queue ("paralysis", "delete_it_if_illusion")


(I'm not sure why you need the other parameter so I'm leaving it there for now.)

If you need to have a case where the note is printed, you could do:
prompt:queue ({aff="paralysis", print_note=false, enable_trigger=false}, "delete_it_if_illusion")

and
prompt:queue ({aff="paralysis", print_note=true, enable_trigger=true}, "delete_it_if_illusion")

etc.

Now you can easily test equality of two affliction chunks. After all you are trying to store data in your queues, not whole functional operations.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
[Go to top] top

Posted by Ksajal   (17 posts)  [Biography] bio
Date Mon 26 Apr 2010 11:32 AM (UTC)  quote  ]

Amended on Mon 26 Apr 2010 01:54 PM (UTC) by Ksajal

Message
Nick Gammon said:

Generally when you seem to have hit a limitation of the language you need to revisit what you are doing. For example, if you are processing afflictions, and you want to queue up a cure, do a simple keyed lookup (or sequential lookup) of your queue of things you are planning to cure, to see if it is there already. But not by trying to compare functions per se. Stick to affliction names or cure names, or something more high level.

This is what I am doing:

-I have a vector with all the afflictions, in the order I want to cure them, from the most dangerous to the least dangerous.
-I have a module affs which adds the affliction when I get the affliction message: affs:add (affliction) (the new affliction is stored in the the affs ["current"] table).

The line for an affliction can be an illusion (another player used a skill to make you see the line). And if it is an illusion, there is a possibility that you detect the illusion before the prompt. You detect it based on a % chance (there is a skill), or by checking against different things (like if the illusion was supposed to prone you, you can check for prone at the next prompt-the prompt shows without a doubt when you are prone-, and a few other means).

Sometimes you can be certain that an affliction line is not an illusion (for that I use affs:add), and other times you cannot (I use the queue for that).

I am not using the queue only for afflictions and I sometimes need the queue to execute a set of functions that are only used with that trigger, like this (just an example):

prompt:queue (function () EnableTrigger ("name") affs:add ("affliction") Note ("AFFLICTION")end)

And I need to be sure I am not queued the same function twice.

When I detect an illusion, I delete certain queued function (for that I use another table entry in the prompt queue), which I previously marked for deletion when I stored them into the queue (this is the previous function, marked for deletion):

prompt:queue (function () EnableTrigger ("name") affs:add ("affliction") Note ("AFFLICTION")end, "delete_it_if_illusion")

That is a little besides the point, the problem still remains, I need an unique name for the function for both comparing with previous entries in the queue, and for storing it for removal in case of an illusion. Problem which I solved by assigning an unique id for the function queued, like this ("affs_add_paralysis" is the id):

prompt:queue (function () affs:add ("paralysis") end, "affs_add_paralysis", "delete_it_if_illusion")
[Go to top] top

Posted by Nick Gammon   Australia  (18,770 posts)  [Biography] bio   Forum Administrator
Date Mon 26 Apr 2010 01:33 AM (UTC)  quote  ]
Message
Twisol said:

If you want a really messed up way to do it you can do this. Nick's going to kill me just for suggesting such an outlandish approach:

string.dump(function() end) == string.dump(function() end)




Apart from the aesthetic considerations, it just doesn't work:


s1 = string.dump (function () print "hi there" end)
s2 = string.dump (function () print "hi there" end)
 
print (s1 == s2)  --> false


s1 = string.dump (function () end)
s2 = string.dump (function () end)

print (s1 == s2)  --> false


Ksajal said:

I think I understand what you mean, but I have hundreds of afflictions, hundreds of cures, hundreds of defenses, and so on, declaring a function for each is just too much.


But you have hundreds of something, right? Because you are testing if one is equal to the other?

Generally when you seem to have hit a limitation of the language you need to revisit what you are doing. For example, if you are processing afflictions, and you want to queue up a cure, do a simple keyed lookup (or sequential lookup) of your queue of things you are planning to cure, to see if it is there already. But not by trying to compare functions per se. Stick to affliction names or cure names, or something more high level.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Twisol   USA  (2,229 posts)  [Biography] bio
Date Sun 25 Apr 2010 11:37 PM (UTC)  quote  ]
Message
Ksajal said:

I think I understand what you mean, but I have hundreds of afflictions, hundreds of cures, hundreds of defenses, and so on, declaring a function for each is just too much.

I've tested my unique ids table solution, it works exactly as it should so far, I'm gonna stick with it.


You're not the first to write a curing system, and others have dealt with that problem already, more or less. Store the functions in your own tables, so they're not loose. Look at ACS2, a somewhat outdated system for Achaea, to see how they've done some of this. I don't recommend it for style or best practices, but it does work...

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Twisol   USA  (2,229 posts)  [Biography] bio
Date Sun 25 Apr 2010 11:30 PM (UTC)  quote  ]

Amended on Sun 25 Apr 2010 11:32 PM (UTC) by Twisol

Message
Ksajal said:
I've tried in my case, it doesn't work

one = function () Note ("") end
two = function () Note ("") end
Note (one == two)-->false


Well, of course. They're two separate instances of a function. In other languages, you wouldn't expect for "new Object() == new Object()".

If you want a really messed up way to do it you can do this. Nick's going to kill me just for suggesting such an outlandish approach:

string.dump(function() end) == string.dump(function() end)


I can't test it right now - posting from my phone - but that should work for most simple cases. I can't guarantee it will if you start throwing in upvalues and modifed environments (setfenv), but it would be interesting to experiment with.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Ksajal   (17 posts)  [Biography] bio
Date Sun 25 Apr 2010 11:16 PM (UTC)  quote  ]
Message
I think I understand what you mean, but I have hundreds of afflictions, hundreds of cures, hundreds of defenses, and so on, declaring a function for each is just too much.

I've tested my unique ids table solution, it works exactly as it should so far, I'm gonna stick with it.
[Go to top] top

Posted by Nick Gammon   Australia  (18,770 posts)  [Biography] bio   Forum Administrator
Date Sun 25 Apr 2010 11:00 PM (UTC)  quote  ]
Message
Ksajal said:


Nick Gammon said:

What is the problem exactly? You can compare functions directly.

I've tried in my case, it doesn't work

one = function () Note ("") end
two = function () Note ("") end
Note (one == two)-->false





They are two functions that happen to do the same thing.


one = function () Note ("") end
two = one
Note (one == two) --> true


In your case, stop inlining the functions if you can. eg. instead of:


prompt:queue (function () affs:add ("affliction")end)


do:



-- define function once
function add_affliction () 
  affs:add ("affliction")
end

-- queue it if required
if something then
  prompt:queue (add_affliction)
end -- if


By only defining functions once, you now can just test if they are the same.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Ksajal   (17 posts)  [Biography] bio
Date Sun 25 Apr 2010 10:50 PM (UTC)  quote  ]
Message
Twisol said:

Your string ID works, certainly, and I'm glad you have a solution. Different functions will never clash, though, while anyone can pass in an already-used string ID. ;)

I'm usually calling prompt:queue from other functions, like this:

function affs:add_queue (name, val)
prompt:queue (function () affs:add (name, val)end, "affs_add_"..name)
end --function

Or if I need to do some very special stuff:

prompt:queue (function () some stuff end, "user_"..tostring (os.time ()))

They won't ever clash, me thinks.

Nick Gammon said:

What is the problem exactly? You can compare functions directly.

I've tried in my case, it doesn't work

one = function () Note ("") end
two = function () Note ("") end
Note (one == two)-->false
[Go to top] top

Posted by Nick Gammon   Australia  (18,770 posts)  [Biography] bio   Forum Administrator
Date Sun 25 Apr 2010 10:37 PM (UTC)  quote  ]
Message
Ksajal said:

But this means I will still have to create an unique name for each function I am registering.


What is the problem exactly? You can compare functions directly.


print (print == print) --> true
print (print == tostring)  --> false


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Twisol   USA  (2,229 posts)  [Biography] bio
Date Sun 25 Apr 2010 10:17 PM (UTC)  quote  ]
Message
Ksajal said:
But this means I will still have to create an unique name for each function I am registering.

If by "name" you mean variable, then yes. If you're giving away a function with no way to refer to it later, there's no reason to expect to be able to deregister it.

Ksajal said:
And you forgot to delete the variable containing the function from the memory when you unregister the function.


I don't see what you mean, sorry. I table.remove and set to nil in Deregister.

Oh, I see. In DoStuff, for the one being used.


Your string ID works, certainly, and I'm glad you have a solution. Different functions will never clash, though, while anyone can pass in an already-used string ID. ;)

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


3,174 views.

This is page 1, subject is 2 pages long: 1 2  [Next page]

[Reply to this subject]  Reply to this subject   [New subject]  Start a new subject   [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

[Home]

Written by Nick Gammon - 5K

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( http://www.gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Internet Contents Rating Association (ICRA) - 2K]    [Web site powered by FutureQuest.Net]