I have a list with special users and normal users. Special users have their own special func, while normal users use a standard func.
I came up with this code design, but I feel that this is not optimal (performance wise).
So my question is: How would I get the best performance when calling inner functions like the example below?
if something then
CallFunc(var)
end
Special/normal user logic
function CallFunc(var)
if table[name] then
table[name](var)
else
Standard_Func(var)
end
end
local table = {
["name1"] = function(var) Spec_Func1(var) end,
["name2"] = function(var) Spec_Func2(var) end,
["name3"] = function(var) Spec_Func3(var) end,
...
--40 more different names and different funcs
}
Special user funcs
function Spec_Func1(var)
--lots of code
end
function Spec_Func2(var)
--lots of code
end
...
--more funcs
EDIT:
see #hjpotter92's answer:
I cant find the user in the table.
local function_lookups = {
name1 = Spec_Func1, --this doesnt let me find the user
--name1 = 1 --this does let me find the user (test)
}
if function_lookups[name] then --this fails to find the user
--do something
end
You do not need another anonymous function. Simply use the lookup table as follows:
local function_lookups = {
name1 = Spec_Func1,
name2 = Spec_Func2,
name3 = Spec_Func3,
...
--40 more different names and different funcs
}
Do not use the variable name table. It is a library available in Lua itself, and you are overwriting it.
You don't need a special function at all! You can use a generic function that's behaviour depends on the caller! Lemme explain with a piece of code:
local Special = {Peter=function(caller)end} --Put the special users' functions in here
function Action(caller)
if Special[caller] then
Special[caller](caller)
else
print("Normal Action!")
end
end
So whenever a user does a certain action, you can fire this function and pass a caller argument, the function then does the work behind the scenes determining if the caller is special, and if so what to do.
This makes your code clean. It also makes it easier to add more than 2 user statuses!
Related
This method works, but I'm sure the performance could be greatly improved. Also, I'm realizing how fun and awesome it is to take smelly code like this, and rubify it. But I need a little more help to get my Ruby skills to the level to refactor something like this.
An objective can have "preassign" objectives. These are pre-requisites that must be completed before the a student can try the objective in question.
ObjectiveStudent is the join model between an objective and a student. It has a method called "points_all_time" that finds the student's best score on that objective.
The check_if_ready method is the one that I'm trying to refactor in this question. It also belong to the ObjectiveStudent model.
It needs to check whether the student has passed ALL of the preassigns for a given objective. If so, return true. Return false if the student has a less-than-passing score on any of the preassigns.
def check_if_ready
self.objective.preassigns.each do |preassign|
obj_stud = self.user.objective_students.find_by(objective_id: preassign.id)
return false if obj_stud.points_all_time < 7
end
return true
end
Right now I suspect this method is making too many calls to the database. What I'm really hoping to find is some way to look at the scores for the pre-reqs with a single db call.
Thank you in advance for any insight.
The following should work for you:
def is_ready?
user.objective_students
.where(objective_id: objective.preassigns.select(:id))
.none? { |obj_stud| obj_stud.points_all_time < 7 }
end
We collect all the objective_students for the user where the objective_id is in the list of objective.preassigns ids. This results in one 1 query being executed.
Then we use Enumerable#none? to make sure that none of the objective_students have points_all_time less than 7.
You could also use the inverse .all? { |obj_stud| obj_stud.points_all_time >= 7 } if you wanted
One way you could "rubify" this method is to rewrite the signature as:
def is_ready?
It is common practice to append ? to functions that return a boolean value in Ruby. (Note: I also don't really see a reason to have the word 'check' in the declaration, but that's just an opinion).
Furthermore, if objective_id is the primary key for the objective_students model, you can simply write objective_students.find(preassign.id) instead of the find_by method.
I would also suggest having a separate method for returning a student's points (especially since I suspect you will need to get a student's points more than just once) :
def getPoints(preAssignId)
return self.user.objective_students.find_by(objective_id: preAssignId).points_all_time
end
Then your main method can be written in a more clear, self-describing manner as:
def is_ready?
self.objective.preassigns.each {|preassign| return false if getPoints(preassign) < 7 }
return true
end
A simple VBA function. When I try to use it in my worksheet, all I get, no matter what I do, is "That name is not valid". I'm out of ideas.
Sub FindABV(temperature)
With Worksheets("Sheet1")
.Range("C28").GoalSeek _
Goal:=temperature, _
ChangingCell:=.Range("B28")
End With
FindABV = .Range("B28").Value
End Sub
I've tried creating a new Module to put it in. No change.
And no error indications from the code editor.
The Sub procedure performs a task and then returns control to the calling code, but it does not return a value to the calling code.
See more here.
This said, you cannot set a procedure equal to something:
FindABV = .Range("B28").Value
because that name is not valid (you cannot say that a procedure is equal to a certain value, it doesn't make sense). You probably wanted to use a Function to return the value of that cell calculated by the Goal Seeker depending on the input temperature that you pass by the function:
Function FindABV(temperature)
With Worksheets("Sheet1")
.Range("C28").GoalSeek _
Goal:=temperature, _
ChangingCell:=.Range("B28")
End With
FindABV = .Range("B28").Value '<-- return the value
End Function
However, be careful: if =FindABV(temperature) lies on Sheet1.Range("B28"), you will have a circular reference because your function will try to have the value of itself.
Your code will not deliver the results you want. If you want to have the Function work for different values than the ones stored in B28 and C28 you'll have to write it more like this:
Public Function FindABV(goalCell As Range, changeCell As Range, temperature As Double)
goalCell.GoalSeek Goal:=temperature, ChangingCell:=changeCell
FindABV = changeCell
End Function
But this doesn't matter in any case because GoalSeek actually changes the value in the ChangingCell which Excel will not do if it is called from within a Function.
For a field inside a deeply nested table, for example, text.title.1.font. Even if you use
if text.title.1.font then ... end
it would result in an error like "attempt to index global 'text' (a nil value)" if any level of the table does not actually exists. Of course one may tried to check for the existence of each level of the table, but it seems rather cumbersome. I am wondering is there a safe and prettier way to handle this, such that when referencing such an object, nil would be the value instead of triggering an error?
The way to do this that doesn't invite lots of bugs is to explicitly tell Lua which fields of which tables should be tables by default. You can do this with metatables. The following is an example, but it should really be customized according to how you want your tables to be structured.
-- This metatable is intended to catch bugs by keeping default tables empty.
local default_mt = {
__newindex =
function()
error(
'This is a default table. You have to make nested tables the old-fashioned way.')
end
}
local number_mt = {
__index =
function(self, key)
if type(key) == 'number' then
return setmetatable({}, default_mt)
end
end
}
local default_number_mt = {
__index = number_mt.__index,
__newindex = default_mt.__newindex
}
local title_mt = {__index = {title = setmetatable({}, default_number_mt)}}
local text = setmetatable({}, title_mt)
print(text.title[1].font)
Egor's suggestion debug.setmetatable(nil, {__index = function()end}) is the easiest to apply. Keep in mind that it's not lexically scoped, so, once it's on, it will be "on" until turned off, which may have unintended consequences in other parts of your code. See this thread for the discussion and some alternatives.
Also note that text.title.1.font should probably be text.title[1].font or text.title['1'].font (and these two are not the same).
Another, a bit more verbose, but still usable alternative is:
if (((text or {}).title or {})[1] or {}).font then ... end
In Lua I've created a pretty printer for my tables/objects. However, when a function is displayed, it's shown as a pointer.
I've been reading up on Lua Introspection but when I introspect the function with debug.getinfo() it won't return the function's name. This seems to be due to a scoping issue but I'm not sure how to get around it.
What is the best way to get a function's name using its pointer? (I understand functions are first class citizens in Lua and that they can be created anonymously, that's fine)
when you create the functions, register them in a table, using them as keys.
local tableNames = {}
function registerFunction(f, name)
tableNames[f] = name
end
function getFunctionName(f)
return tableNames[f]
end
...
function foo()
..
end
registerFunction(foo, "foo")
...
getFunctionName(foo) -- will return "foo"
For some reason, it seems to work only with number parameters (that is, active functions on the stack).
The script
function a() return debug.getinfo(1,'n') end
function prettyinfo(info)
for k,v in pairs(info) do print(k,v) end
end
prettyinfo(a())
prints
name a
namewhat global
but if I change the last line to
prettyinfo(debug.getinfo(a, 'n'))
it gives me only an empty string:
namewhat
In the Lua language, I am able to define functions in a table with something such as
table = { myfunction = function(x) return x end }
I wondered if I can created methods this way, instead of having to do it like
function table:mymethod() ... end
I am fairly sure it is possible to add methods this way, but I am unsure of the proper name of this technique, and I cannot find it looking for "lua" and "methods" or such.
My intention is to pass a table to a function such as myfunction({data= stuff, name = returnedName, ?method?init() = stuff}).
Unfortunately I have tried several combinations with the colon method declaration but none of them is valid syntax.
So...anyone here happens to know?
Sure: table:method() is just syntactic sugar for table.method(self), but you have to take care of the self argument. If you do
tab={f=function(x)return x end }
then tab:f(x) won't work, as this actually is tab.f(tab,x) and thus will return tab instead of x.
You might take a look on the lua users wiki on object orientation or PiL chapter 16.