Serialization can fails with a class object created containing __pairs:
test = torch.class('test')
function test:__init()
self.data = {}
end
function test:__pairs(...)
return pairs(self.data, ...)
end
function test:get_data()
print(self.data)
end
a = test.new()
a.data = {"asdasd"}
b = torch.serialize(a)
c = torch.deserialize(b)
print(torch.typename(c))
print(c:get_data())
The following returns:
test
nil
The engine behind the torch.serialization is located in the File-class. The File:writeObject us the key function. For the above example the action for a Torch class starts at line 201 with the:
elseif typeidx == TYPE_TORCH then
The type is identified in the File:isWritableObject.
One could probably implement the metatable function write but in the above example the problem was non-torch metatable function __pairs that should be __pairs__ (see torch.getmetatable):
test = torch.class('test')
function test:__init()
self.data = {}
end
function test:__pairs__(...)
return pairs(self.data, ...)
end
function test:get_data()
print(self.data)
end
a = test.new()
a.data = {"asdasd"}
b = torch.serialize(a)
c = torch.deserialize(b)
print(torch.typename(c))
print(c:get_data())
This gives the expected:
test
{
1 : "asdasd"
}
Related
I have the following object:
local Game = {}
function Game:new(aNumberOfPlayers, aPlayer1, aPlayer2)
self.NumberOfPlayers = aNumberOfPlayers
self.Player1 = aPlayer1
self.Player2 = aPlayer2
self.Id = HttpService:GenerateGUID(true)
self.Status = "Waiting"
self.Moves = {}
self.Position = GetInitialGamePosition()
return self
end
local Square = {}
function Square:new(x, y, index, color)
self.X = x
self.Y = y
self.Index = index
self.Color = color
return self
end
That uses following function to intialize the 2d array for Position
function GetInitialGamePosition()
local mt = {} -- create the matrix
for i=1,15 do
mt[i] = {}
for j=1,15 do
mt[i][j] = Square:new(i,j,GetIndexFromRowColumn(i,j),nil)
end
end
return mt
end
Problem here is that since tables pass by reference each element of the 2d array ends up being the same. In other words when i iterate over a Position every element has same row, column, and index. Not sure what the best way to get around this is?
function Square:new(x, y, index, color)
local o = {}
o.X = x
o.Y = y
o.Index = index
o.Color = color
setmetatable(o, self)
self.__index = self
return o
end
I am working on translating the word search algorithm implemented in both Julia (for the main code -- https://rosettacode.org/wiki/Word_search#Julia) and Python (for the creation of the class for Grid -- https://rosettacode.org/wiki/Word_search#Python).
I am attempting to rewrite the class definition of Grid from Python (see below) into R:
class Grid:
def __init__(self):
self.num_attempts = 0
self.cells = [['' for _ in range(n_cols)] for _ in range(n_rows)]
self.solutions = []
The following is my attempt at translating the Python class into an R6 class:
library("R6")
Grid <- R6Class("Grid",
public = list(
num_attempts = NULL,
cells = NULL,
solutions = NULL,
initialize = function(num_attempts = NA, cells = NA, solutions = NA) {
self$num_attempts <- 0
self$cells <- cells
self$solutions()
},
cells = function(val) {
for (val in seq_along(ncols)) {
for (val in seq_along(nrows))
{
result <- vector("character")
result
}
}
}
)
)
The following is the error message that I receive in R:
Error in R6Class("Grid", public = list(num_attempts = NULL, cells = NULL, :
All items in public, private, and active must have unique names.
Please offer suggestions on how to correctly perform this translation.
Thank you.
You refer to cells twice. Once you set it to Null, then to a function. That’s causing your error, I believe.
I know that you can use tables in a similar way to pointers in lua. That being said, what would pointers to pointers look like? Would they look something like dp = {p = {}}? if so what would the equivalent to the c code below be in lua?
void InsertItem(node **head, node *newp){
node **dp = head;
while((*dp) && (*dp)->value > newp->value
{
dp = &(*dp)->next;
}
newp->next = *dp;
*dp = newp;
}
Yes, double pointer may be translated to Lua as nested table.
local function InsertItem(head, newitem)
while head.next and head.next.value > newitem.value do
head = head.next
end
newitem.next = head.next
head.next = newitem
end
-- Typical Usage:
local head = {}
InsertItem(head, {value = 3.14})
InsertItem(head, {value = 42})
InsertItem(head, {value = 1})
-- Now the data is the following:
-- head = {next = elem1}
-- elem1 = {next = elem2, value = 42 }
-- elem2 = {next = elem3, value = 3.14}
-- elem3 = { value = 1 }
The big difference between C pointers and Lua tables is that in C, you can take the address of a variable and pass it to a function to modify it. You can't do that in Lua, but the function could always return the modified value.
Would they look something like dp = {p = {}}?
Yes, that's about as close as close as you can get to a pointer to a pointer in Lua.
if so what would the equivalent to the c code below be in lua?
Linked lists tend to work more smoothly with recursion:
local function InsertItem(head, newp)
if not head or head.value <= newp.value then
newp.next = head
return newp
end
head.next = InsertItem(head.next, newp)
return head
end
I have a function that looks for a file named "global" in parent directories of the working dir. This is how I imagined it:
function readglobal()
if isfile("./global")
text = readdlm("./global",String,comment_char='/')
else
for i = 1:8
if isfile("../"^i * "global")
text = readdlm("../"^i * "global",String,comment_char='/')
break
end
end
end
isdefined(:text) || error("Could not find global file")
dict = Dict{String,String}()
for i in 1:size(text)[1]
dict[text[i,1]] = text[i,2]
end
return dict
end
This doesn't work because isdefined looks for global variables in the current_module(), where I call the function from.
Is there a way to make it work as intended? To evalute isdefined(:text) inside the function?
I worked around this with the following code, but I think the code above is cleaner.
function readglobal()
foundit = isfile("./global")
if foundit
text = readdlm("./global",String,comment_char='/')
foundit=true
else
for i = 1:8
foundit = isfile("../"^i * "global")
if foundit
text = readdlm("../"^i * "global",String,comment_char='/')
break
end
end
end
foundit || error("Could not find global file")
dict = Dict{String,String}()
for i in 1:size(text)[1]
dict[text[i,1]] = text[i,2]
end
return dict
end
Edit: Somehow I missed that you found the workaround, as you call it, which is pretty much the same as I suggested. I disagree that the first code is cleaner, using isdefined seems hacky to me. A foundit flag is the right way, IMHO.
Original answer:
Don't use isdefined to check whether the file has been found. Instead set a flag, e.g. filefound. Something along these lines (warning, untested):
function readglobal()
filefound = false
filepath = "global"
for i in 0:8
filefound = isfile(filepath)
if filefound
break
end
filepath = joinpath("..", filepath)
end
filefound || error("Could not find file ")
text = readdlm(filepath, String, comment_char='/')
dict = Dict{String,String}()
for i in 1:size(text, 1)
dict[text[i,1]] = text[i,2]
end
return dict
end
Edit 2: Here's a variant:
function readglobal(filename, maxtries=8)
tries = 0
while !isfile(filename) && (tries+=1) <= maxtries
filename = joinpath("..", filename)
end
tries > maxtries || error("Could not find file ")
text = readdlm(filename, ...
...
end
The following is a 1.5-line version of this function:
readglobal() = Dict(mapslices(x->=>(x...),readdlm(first(filter(isfile,
"./$("../"^i)global" for i=0:8)),String;comment_char='/'),2))
It even returns an error if the file is missing ;)
Not an exact answer, but I would use a separate function:
function get_global_content()
if isfile("./global")
return readdlm("./global",String,comment_char='/')
else
for i = 1:8
if isfile("../"^i * "global")
return readdlm("../"^i * "global",String,comment_char='/')
end
end
end
error("Could not find global file")
end
function readglobal()
text = get_global_content()
dict = Dict{String,String}()
for i in 1:size(text)[1]
dict[text[i,1]] = text[i,2]
end
return dict
end
Alternatively, have a look at Nullable, e.g.,
function readglobalnull()
text = Nullable()
if isfile("./global")
text = Nullable(readdlm("./global",String,comment_char='/'))
else
for i = 1:8
if isfile("../"^i * "global")
text = Nullable(readdlm("../"^i * "global",String,comment_char='/'))
break
end
end
end
isnull(text) && error("Could not find global file")
text = get(text)
dict = Dict{String,String}()
for i in 1:size(text)[1]
dict[text[i,1]] = text[i,2]
end
return dict
end
Version 0.7 of Julia has a #isdefined variable_name macro that is able to do precisely what I asked for in this question. It should work for any local variable.
I have this code
Option = { }
function Option.nothing( )
local self = { isNone = true, isSome = false }
function self:orElse( alt )
return alt
end
function self:map( f )
return Option.nothing( )
end
function self:exec( f )
end
function self:maybe( alt, f )
return alt
end
return self
end
function Option.just( val )
local self = { isNone = false, isSome = true }
local value = val
function self:orElse( alt )
return value
end
function self:map( f )
return Option.just( f(value) )
end
function self:exec( f )
f( value )
end
function self:maybe( alt, f )
return f(value)
end
return self
end
function printOpt( opt )
local str = opt.maybe( "Nothing", function(s) return "Just " .. s end )
print( str )
end
x = Option.nothing( )
y = Option.just( 4 )
printOpt(x)
printOpt(y)
But I keep getting 'attempt to call local 'f' (a nil value)' here:
function self:maybe( alt, f )
return f(value)
end
It seems I'm having trouble calling a function passed as a argument.
You declared the function as self:maybe(), but you're calling it as opt.maybe(). You should call it as opt:maybe().
Declaring it as self:maybe(alt, f) is equivalent to declaring it as self.maybe(self, alt, f). So if you call it with a . you need 3 args. You're passing 2, so self ends up as "Nothing", and alt ends up as the function object.
However, by calling it as opt:maybe("Nothing", f) this is equivalent to saying opt.maybe(opt, "Nothing", f) which provides the required 3 args.