I'm new to Lua "classes" (metatables) and I have a doubt.
In the following constructor code that I wrote, I declared the variable obj as local. But in most examples on the web, this variable is just assigned to without a local declaration. So in my understanding, it becomes a global variable (not efficient from what I understood). But is there a reason for that?
A = {}
A.__index = A
function A:new(obj_init)
local obj = obj_init or {val = 0}
setmetatable(obj, A)
return obj
end
I also noticed that members of the class can be accessed directly, even from another Lua module:
x = A:new{val = 2}
print(x.val)
But is there a way to make val a private member? Maybe also using local?
First, let's look at what these examples you found might have looked like.
Parameters: Implicit locals
function A:new(obj)
obj = obj or {val = 0}
...
end
in this snippet, obj is a local variable. This is because all function parameters in Lua are local variables. We may rewrite the function as follows to highlight this:
function A:new(...)
local obj = ...
obj = obj or {val = 0}
end
I assume this is what you saw e.g. in the PIL. You probably renamed the parameter to obj_init, losing the implicit local declaration of obj.
Global assignment
If you happened to consume particularly bad resources, you might have seen the following:
function A:new(obj_init)
obj = obj_init or {val = 0}
...
end
in this snippet, obj is indeed a global variable. This is very bad for multiple reasons:
Efficiency: You are right - excepting pathological cases, global variables are always slower than local variables as global variables are entries in the (hash part of the) _G table whereas locals are stored in fast registers of the Lua VM.
Code quality: Global pollution: This constructor now has a side effect: It modifies the global variable obj and expects it to not be modified during its execution. This might lead to this function overwriting a global variable obj and, even worse, you may not yield from a coroutine in the constructor now, because you're dependent on a global state which may not be altered.
Private members
The typical way to implement private table fields in Lua is by convention: You may prefix the field names with an underscore to indicate that these fields may not be modified from outside. Of course programmers are free to circumvent this.
Otherwise, the concept of "private" variables doesn't mesh too well with the scripting language nature of Lua; you can shoehorn full-fledged OOP onto Lua using metatables, but it will be neither idiomatic nor efficient.
Upvalues
The most idiomatic way to implement private members in Lua is to have them be upvalues of closures ("accessors"):
A = {}
A.__index = A
function A:new(obj_init)
local obj = {} -- empty object: only member is private
local val = obj.val
-- note: this does not need `self`, thus no `:` is used;
-- for setters you might want to discard `self` for consistency
function obj.getVal()
return val
end
setmetatable(obj, A)
return obj
end
x = A:new{val = 2}
print(x.getVal())
-- val can not be set from outside (excepting the debug library);
-- it is "private" and only accessible through the getter method
The downside is that all functions accessing your private members will have to be instantiated with each object creation.
Note that even upvalues aren't fully "private" as they may be accessed through the debug library.
debug library workarounds
The debug library allows you to inspect the stack. This allows you to tell which method triggered your __index metamethod. You could thus return different values to different callers. This may be nice for a proof-of-concept to showcase Lua's metaprogramming capabilities, but should not be done in practice as it is very inefficient and hacky.
Related
I tried to change an attribute value of a class by invoking one of its member function:
p1 = tank();
p1.checkOri(p1);
And in the class definition, I have that static method:
classdef tank
properties
value
...
end
methods
...
methods (Static)
function obj = checkOri(obj)
if (CONDITION) %the thing I want it to do
obj.value = EXPRESSION;
...
Yet this checkOri method is not working. But if I write this method in the main file, or to say altering the value of p1-the instance of class tank-it works perfectly:
p1 = tank();
p1.checkOri(p1);
if (CONDITION) %the thing I want it to do
p1.value = EXPRESSION;
It works perfectly.
I wonder what caused this. From my experience with other programming languages, invoking method should have worked, is it because of some tricks with Matlab syntax or static method? How could I fix it so that this method would work?
So, as #Navan in the comment said, handle class could be a solution.
It appears Matlab has a similar parameter concept with Java and C++, arguments modified in a function/method only remains that modification inside the function/method.
For this class, I simply added < handle in the head of class definition and it worked:
classdef tank < handle
properties
...
But I am not sure if that is the only solution, there might be better ways to do this. So I'll leave that question open, you are more than welcomed to post your opinion:D
In MATLAB, the call
p1.checkOri();
is equivalent to
checkOri(p1);
In both cases, the class method checkOri is called for the class of object p1, passing p1 as first argument to the function by value.
Because p1 is passed by value, any changes made to it inside the function are not seen by the object in the calling workspace. Therefore, one typically does
p1 = checkOri(p1);
This way, the object that was passed by value and modified inside the function is passed back out and assigned to the variable that held the original object.
If the method is written as follows:
function obj = checkOri(obj)
%...
end
then MATLAB will optimize the above function call such that no copy of the object is actually made. Note that both in the function declaration and in the function call, the input and output variable is the same.
As already discovered by OP, the above does not hold for handle classes, classes that inherit from handle. These classes act as if they are always passed by reference, and any change made to them in any workspace will be reflected in all other copies in other workspaces.
Also assigning to a member variable does not follow the above, such that
p1.value = 0;
modifies object p1.
For more information on the difference between value classes and handle classes see this other question.
In my example, I have a class representing a certain set of data. Some of the data's properties are written to the class' properties, while the class' methods mostly perform tasks like reading the raw data from spreadsheets and doing some pre-calculations.
I was wondering if the following is according to the "pure doctrine" of OOP, and if not, if and how it could be syntactically improved.
Here is a very simple (untested) implementation of such a class.
classdef dataObjectTest < handle
properties
filename char
pathFilename char
rawData double
end
methods
function obj = setPathnameFromFilename(obj, filename)
%setPathnameFromFilename Determine full path- & filename from single filename
% filename: Name of the file containing the raw data, e.g., 'Test.xls'
obj.filename = filename;
intermed = dir(obj.filename);
obj.pathFilename = fullfile(intermed.folder, obj.filename);
end
function obj = loadRawDataFromSpreadsheet(obj)
% loadRawDataFromSpreadsheet Convert the raw data stored in a spreadsheet into a Matlab
% array, using the full path- & filename determined by setPathnameFromFilename
% rawData: Array contating the raw data
obj.rawData = xlsread(obj.pathFilename);
end
end
end
And here is how one would call this class from another program/script:
test = dataObjectTest;
test.setPathnameFromFilename('Test.xls');
test.loadRawDataFromSpreadsheet;
I am especially concerned about the third line. Since both input and output arguments of the method loadRawDataFromSpreadsheet are properties of the class, it is unnecessary to explicitly define them in the function header. On the other hand, this implementation seems somehow awkward to me and not in "spirit" of OOP, which is a lot about clearly defined interfaces between the user and the class.
So although my code works, I'm still wondering if this is "the right way" to do it or if could be significantly improved.
UPDATE: Admittedly, the choice of my methods' names may have been misleading, but this was not the point of the question. So let me try to clarify.
The first method takes the user-given string filename and returns pathFilename. But since this is also a property of the class, it is not visible from the function signature, i.e., the function should look like:
function pathFilename = setPathnameFromFilename(obj, filename)
But this doesn't work in Matlab. (The varName = part corresponds to return varName in other languages.)
The second method returns the array rawData, and since the input argument pathFilenameis, again, a property of the class, neither are visible in the method's signature.
So my concern was about having methods which actually have in- and output arguments, but do not reveal them through their signature.
It's basically fine, but I'd implement it like this:
classdef dataObjectTest < handle
properties
filename char
pathname char
rawData array
end
methods
function loadRawDataFromSpreadsheet(obj, filename)
obj.filename = filename;
obj.pathname = dataObjectTest.extractPathName(filename
obj.rawData = xlsread(obj.pathname);
end
end
methods (Static, Access = private)
function pathname = extractPathName(filename)
intermed = dir(filename);
pathname = fullfile(intermed.folder, filename);
end
end
end
Notes:
Since it's a handle object, you don't need obj as an output argument of the main method.
I've moved the extraction of the path to a private static method, as it's really a utility function (you could instead implement as an actual subfunction rather than a method).
I've renamed the main method to start with load rather than get, to make sure it isn't mistaken for a property get method.
I wouldn't worry too much about the "spirit of OOP" - instead, just make sure your code works, is well-organised, is testable, and maintainable.
It is just fine according to the "doctrine" of pure OOP for a method to have no in or out parameters apart from the object reference.
However, what you are doing doesn't conform to normal practice for method naming. A method with a name starting with get is normally a "getter". The primary purpose of a "getter" is to return some component of the class. Generally speaking, a "getter" should not modify the target object.
But you have two get... methods that 1) modify the target object and 2) don't return anything.
In my opinion:
the first one should be named setPathnameFromFilename or maybe just setFilename.
the second one should be named loadRawDataFromSpreadsheet or something like that.
On the other hand, this implementation seems somehow awkward to me and not in "spirit" of OOP, which is a lot about clearly defined interfaces between the user and the class.
I actually don't see that at all. Sure, the interface is not clearly defined, but that is largely because you have not documented the methods and because you have chosen (IMO) misleading / non-informative class and method names.
(Disclaimer: I am a Java programmer. However, the basic principles of OOP are largely the same for all OO languages.)
In D, can I initialize directly on declaration and expect the initializer expressions are part of the constructor?
I came from C# and there this is the case. But with DMD 2.071.0 Im getting other behavior.
class Other { }
class Test { Other nonStaticMember = new Other; }
void test()
{
auto t1 = new Test;
auto t2 = new Test;
// Assert is failing, the two Test instances are
// being initialized to the same reference
// instead of execute the Other constructor twice.
assert(t1.nonStaticMember !is t2.nonStaticMember);
}
If this is the intented behavior it should be documented here: https://dlang.org/spec/class.html right?
This code doesn't do in D what it would do in C#.
In your example, Other is instantiated during compilation.
I.e. Other is instantiated once, during compilation, and is placed in the program's data segment. Then, nonStaticMember's initial value will, by default, point to that instance of Other, for all Test instances.
So, everything is working exactly as designed, even if it may be surprising when coming from other languages.
If this is the intented behavior it should be documented here: https://dlang.org/spec/class.html right?
Perhaps, but note that this behavior is not at all specific to classes. A pointer to any value allocated on the heap, as the initial value of a global or local static variable, will behave the same. Whenever the value of an expression is demanded during compilation (and that includes initializers for global/static variables), D attempts to evaluate it at compile-time. A few years ago, this has been extended to allocating values on the "heap" too, which then end up in the program's initial data segment.
I'm using CoffeeScript to create a class and build a private method, but my code feels kludgy.
As in the example below, first I define the method with = and then I am forced to use the call method on the portion to be used. But this seems like a kludgy workaround, so I want to know if there is a cleaner solution.
class Human
constructor: (#name, #height, #weight) ->
_realWeight = ->
#weight
answerWeight: ->
console.log(_realWeight.call(#) - 5)
$ ->
ken = new Human('Ken', 165, 70)
ken.answerWeight()
TL;DR
No.
Longer Answer
There is only one way to have truly private data in javascript/coffeescript: closures.
First, lets consider some alternatives:
Symbols
Because symbols are unique they can be used to create psuedo-private data:
you can only access the property if you have a reference to the symbol its keyed to:
foo = Symbol('I am unique')
bar = {}
bar[foo] = "I am almost private"
Code that doesn't have access to foo can't easily get to that property of bar except for Object.getOwnPropertySymbols. So not easy to break, but breakable.
Underscores
Typical naming convention says that properties/methods prefixed or followed by an underscore are 'private', they are not to be used by an external caller. However, that 'privacy' is not in any way enforced by the runtime.
So lets talk about closures.
Simple Closure example
makeFoo = (something) -> getSomething: -> something
foo = makeFoo(3)
foo.something # undefined
foo.getSomething() # 3
Now there is no way to get at the parameter passed to the constructor except to call the method. This pattern, while slightly more elegant in coffeescript, is still kinda lame. Lots of duplicated function objects. Not so bad for just getSomething, but add a bunch of methods and it gets ugly fast. Also, typically not as easily optimized by the JIT compiler as foo = new Foo() would be. Fortunately, ES 2015 to the rescue:
Advanced Closure Example
Foo = null
do ->
privateData = new WeakMap()
getSomething = -> privateData.get(this)
Foo = class Foo
constructor: (something) -> privateData.set(this, something)
getSomething: getSomething
foo = new Foo(3)
foo.something # undefined
foo.getSomething() # 3
new Foo(42).getSomething() # 42
foo instanceof Foo # true
Now all instances of Foo share one copy of getSomething rather than each getting their own. The weakmap is hidden in the closure created by the IIFE, and because of the 'weak' part of WeakMap when the instance gets garbage collected the private data will be as well. You are also now potentially able to enjoy the benefits of the compiler optimizing newly created objects. Last but not least, instanceof still works properly (to the extent that it ever works properly).
Further reading.
Even More reading
Note
WeakMaps are not supported in all browsers (for IE its 11 or bust). There is a shim, but it cannot be completely polyfilled. Whether or not the shim gets close enough is a call you'll have to make.
I am trying to use global variable in Scala. to be accessible in the whole program .
val numMax: Int = 300
object Foo {.. }
case class Costumer { .. }
case class Client { .. }
object main {
var lst = List[Client]
// I would like to use Client as an object .
}
I got this error :
error: missing arguments for method apply in object List;
follow this method with `_' if you want to treat it as a partially applied function
var lst = List[A]
How can I deal with Global Variables in Scala to be accessible in the main program .
Should I use class or case class in this case ?
This isn't a global variable thing. Rather, you want to say this:
val lst = List(client1, client2)
However, I disagree somewhat with the other answers. Scala isn't just a functional language. It is both functional (maybe not as purely as it should be if you ask the Clojure fans) and object-oriented. Therefore, your OO expertise translates perfectly.
There is nothing wrong with global variables per se. The concern is mutability. Prefer val to var as I did. Also, you need to use object for singletons rather than the static paradigm you might be used to from Java.
The error you quote is unrelated to your attempt to create a global variable. You have missing () after the List[Client].
If you must create a global variable, you can put it in an object like Foo and reference it from other objects using Foo.numMax if the variable is called numMax.
However, global variables are discouraged. Maybe pass the data you need into the functions that need it instead. That is the functional way.