I've found that I can use private variables in coffeescript classes like so:
class Book
title = null
numberOfPages = null
constructor: (t, nop) ->
title = t
numberOfPages = nop
ripOutPages: (numPages) -> numberOfPages = numberOfPages - numPages
isEmpty: -> numberOfPages == 0
So my first question is, is this considered a reasonable approach in coffeescript?
And my second question is, is there a neater way to achieve this (i.e. not having to initialise the variables in the class body then assign them in the constructor)?
Thanks,
Tom
If you look at the generated JS code, you will notice that those are more like "private" static class properties, not "private" instance properties:
var Book;
Book = (function() {
var numberOfPages, title;
title = null;
numberOfPages = null;
function Book(t, nop) {
title = t;
numberOfPages = nop;
}
Book.prototype.ripOutPages = function(numPages) {
return numberOfPages = numberOfPages - numPages;
};
Book.prototype.isEmpty = function() {
return numberOfPages === 0;
};
return Book;
})();
Every instance you create shares the same title and numberOfPages variables. So I guess the answer is: No, it's not a suitable approach for what you are trying to do.
JavaScript simply doesn't have "private" properties (yet).
If you really-really want "private" variable, you might want to define your methods as closures:
class Book
constructor: (t, nop) ->
# Those are two local variables:
title = t
numberOfPages = nop
# The following closures will have access to the two variable above:
#title = -> title # <- accessor to title
#numberOfPages = -> numberOfPages # <- accessor to numberoOfPage
#ripOutPages = (numPages) -> numberOfPages = numberOfPages - numPages
isEmpty: -> #numberOfPages() == 0
# ^^^^^^^^^^^^^^^^
# declared "as usual" as it uses accessor to access the "private" variables
# Some tests
lotr = new Book("The Lord of the Rings",1137)
hobbit = new Book("The Hobbit",276)
console.log lotr.title(), lotr.numberOfPages()
console.log hobbit.title(), hobbit.numberOfPages()
lotr.ripOutPages 100
console.log lotr.title(), lotr.numberOfPages()
Producing:
The Lord of the Rings 1137
The Hobbit 276
The Lord of the Rings 1037
Related
Currently, this shows 2 variables on the screen. Whenever that variable changes, it is also shown on the GUI.
I would like to bind array indexes in a similar way. For example: x[1],
and whenever x[1] changes, so does the value shows on GUI
EDIT: array x doesn't update, I also don't want the whole array but each index on a new line.
import groovy.swing.SwingBuilder
import groovy.beans.Bindable
#Bindable
class controller{
boolean stop = false;
String status = "RUNNING";
String name = "";
String[] x= new String[5];
}
def ctrl = new controller();
def UI = new SwingBuilder().edt {
frame(title: 'Menu', size: [220, 150], locationRelativeTo: null, show: true, alwaysOnTop: true){
gridLayout(cols:1, rows: 5)
label(text: bind(source: ctrl, sourceProperty: 'status', converter: { v -> v? "Status: $v": ''}))
label(text: bind(source: ctrl, sourceProperty: 'name', converter: { v -> v? "$v": ''}))
label(text: bind(source: ctrl, sourceProperty: 'x', converter: { v -> v? "$v": ''}))
}
}
for(i = 0; i < 5 ; i++){
sleep(500);
ctrl.name+= "Hi there ";
ctrl.x[i] = "T"+i;
}
ctrl.status = "DONE";
sleep(1000);
UI.dispose();
You can't observe changes on an array using #Bindable in this way. The AST transformation is a convenience for registering methods that rely on PropertyChange and PropertyChangeListener.
Changes made to name and status properties work because you're replacing their value, thus a PropertyChangeEvent is triggered for every change. However for the x property you're not changing the array reference, but the elements within the array.
You have two options to make this work:
either observe changes on the index itself (add an Integer property to the controller class).
use an ObservableList instead of an array.
Personally I prefer option #1. You will have to use a converter such as
label(text: bind(source: ctrl, sourceProperty: 'index', converter: { v -> v != -1? ctrl.x[v]: ''}))
Notice the use of -1 to check for a selected index as a value of 0 would make the previous check (v?) fail due to Groovy Truth.
The controller class can be updated as follows
#Bindable
class controller{
boolean stop = false;
String status = "RUNNING";
String name = "";
String[] x= new String[5];
int index = -1;
}
following problem is mine:
i want to have a function that create a new object in lua, but it should be possible to extend it.
function Class(table)
local a = {}
local t = {create = _create, __newindex = function(o,k,v)
if k == "create" then
--getmetatable(o).create = function()
--_create(o)
--v()
--end
-- or just create(v.params)
else
rawset(o,k,v)
end
end,
}
setmetatable(a,t)
t.__index = t
end
function _create(o,...)
return newTable
end
ele = Class:create()
function Class:create( n )
self.name = n
end
ele2 = Class:create("bbbb")
now the ele2 is without a name, but it schould be create a new object with the given string as name.
can i get the parameter of given value(type function) from newindex or can i execute the value?
There are a few things I'm not sure about. As Etan said, what is newTable and why are you trying to set create as a function of Class when Class is a function?
If you're looking for a way to init an instance of a class when it is created, you can do something like this:
function Class()
local class = {}
class.__index = class
return setmetatable(class, {__call = function(...)
local instance = setmetatable({}, class)
if instance.init then
instance:init(select(2, ...))
end
return instance
end})
end
--now an example:
Dog = Class()
function Dog:init(name)
self.name = name
end
function Dog:bark()
print(string.format("%s barked!", self.name))
end
local pedro = Dog("Pedro")
pedro:bark() --> pedro barked!
I've got a function which loads various models, and currently have this kind of setup:
if(message == "user") {
var model = User.findAll(
("room" -> "demo")
)
} else if (message == "chat") {
var model = Chat.findAll(
("room" -> "demo")
)
}
This is really clunky as I aim to add lots more models in future, I know in javascript you can do something like this:
var models = {
"user" : load_user,
"chat" : load_chat
}
Where "load_user" and "load_chat" would load the respective models, and so I can streamline the whole thing by doing:
var model = models[message]();
Is there a way I can do something similar in Scala, so I can have a simple function which just passes the "message" var to a List or Object of some kind to return the relevant data?
Thanks in advance for any help, much appreciated :)
In Scala you can do:
val model = message match {
case "user" => loadUser() // custom function
case "chat" => loadChat() // another custom function
case _ => handleFailure()
}
You can as well work with a Map like you did in your JavaScript example like so:
scala> def loadUser() = 1 // custom function
loadUser: Int
scala> def loadChat() = 2 // another custom function
loadChat: Int
scala> val foo = Map("user" -> loadUser _, "chat" -> loadChat _)
foo: scala.collection.immutable.Map[java.lang.String,() => Int] = Map(user -> <function0>, chat -> <function0>)
scala> foo("user")()
res1: Int = 1
Pay attention to the use of "_" in order to prevent evaluation of loadUser or loadChat when creating the map.
Personally, I'd stick with pattern matching.
I have a Lua class like below. I am using json to serialize the object and put it in a key value store. I am able to serialize the object and put it in the key value store successfully but i am not able to call any methods of the object after i retrieve the object from the key value store. I understand the json module skips the methods while encoding and my object does not have methods after decoding.
Is there a way to append methods to the class after i decode the object from json to lua ? some thing similar to function pointers in C language.
local class_name = "user_object";
user_object = {}; --user class
function user_object.new (mobile, password, uid)
local self = {};
self.mobile = mobile;
self.uid = uid; -- generate a uid which is a running number.
self.password = password;
self.messages_sent = 0;
self.put_request_count = 0;
self.get_request_count = 0;
self.last_time_active = "";
self.get_tickets = {};
self.put_tickets = {};
self.group_message_stream = {};
self.group_ownerships = {}; -- group names which he is owner of
self.group_memberships = {}; -- group names which he is member of
self.sent_poke_count = 0;
self.sent_poke_stream = {};
self.recv_poke_count = 0;
self.recv_poke_stream = {};
function self:add_put_ticket(ticketid)
table.insert(self.put_tickets, ticketid);
self:incr_put_count();
self:save();
return;
end
function self:add_get_ticket(ticketid)
table.insert(self.get_tickets, ticketid);
self:incr_get_count();
self:save();
return;
end
Function in Lua are first class objects, you can store a function in any variable. The line
function self:add_put_ticket(ticketid)
is equivalent to
self.add_put_ticket = function (self, ticketid)
From there, it should be obvious what to do: define your desired methods where they are accessible and assign them to the appropriate fields after deserialization
You can do this with metatables.
user = { name = 'ponzao' } -- Just a table with values.
User = {} -- Table containing the functions.
function User:allCapsName() return self.name:upper() end -- A method.
setmetatable(user, {__index = User}) -- For unavailable keys all calls are dispatched to User.
print(user:allCapsName()) --> "PONZAO"
I want to test if an object is a vector, any vector, not only a vector of a single type.
I ran a test:
var v:Vector.<int> = new Vector.<int>();
v.push(3);
v.push(1);
v.push(2);
trace(v is Array); // false
trace(v is Vector); // false
trace(v is Vector.<int>); // true
trace(v is Vector.<*>); // false
It seems that the only thing that returns true is the one which specifies the vector type, but I want to test it for ANY type.
I will need a very efficient method to compare, because getQualifiedClassName is too slow.
My current approach is:
private static function isVector(obj:Object):Boolean {
return (getQualifiedClassName(obj).indexOf('__AS3__.vec::Vector') == 0);
}
But it is 2x slower than the is operator.
I need speed because it's for a object serialization class, and it needs to be very fast.
The problem is that Vector.<*> is a different class than that used for <Number>, <int>, or <uint>. The numeric primitives have special classes for better efficiency. String and Boolean are also primitives, but unlike the numeric primitives they are detected by <*>. As a result, you need only test for the generic Vector and the 3 numeric types.
This solution is over 2 times as fast as getQualifiedClassName in the worst case where the object is either not a Vector, or is a Vector.<uint>, and 5 times faster if the object is a non-primitive base type Vector, like Vector.<Object>:
return (obj is Vector.<*>
|| obj is Vector.<Number>
|| obj is Vector.<int>
|| obj is Vector.<uint>);
Here's a simplistic test:
var moo:Vector.<uint> = new Vector.<uint>();
var timer:Timer = new Timer();
var b:Boolean;
timer.startTimer();
for (var i:int = 0; i < 1000000; i++)
{
b = (moo is Vector.<*>
|| moo is Vector.<Number>
|| moo is Vector.<int>
|| moo is Vector.<uint>);
}
logger.info(" is timer: " + timer.endTimer());
timer.startTimer();
for (i = 0; i < 1000000; i++)
{
b = (flash.utils.getQualifiedClassName(moo).indexOf('__AS3__.vec::Vector') == 0);
}
logger.info("gqcn timer: " + timer.endTimer());
[LOG] com.tcg.test: is timer: 320
[LOG] com.tcg.test: gqcn timer: 756
Change moo to Vector.<Object>:
[LOG] com.tcg.test: is timer: 158
[LOG] com.tcg.test: gqcn timer: 743
Other methods are way too inefficient, so I'm still using my approach:
private static function isVector(obj:Object):Boolean {
return (getQualifiedClassName(obj).indexOf('__AS3__.vec::Vector') == 0);
}
trace(new Array().fixed);//undefined
trace(new Object().fixed);//undefined
trace(new Vector.<Sprite>().fixed);//false
trace(new Vector.<*>().fixed);// false
If you need serialization for any kind of object, you have to iterate over all possible types anyway, so you could use a sequential approach to find your vector type:
v is ... (simple data types)
v is ... (object types that are not collections)
v is Array
v is XMLList
v is ... (all other collection types you can think of)
if none of the above is true, it must be a vector
serialize objects in the vector. If you have more than one type, it's Vector.<*>, otherwise set the vector type according to the object type of the content items.
Use
(obj as Vector.<*>) is Vector.<*>
/// Return Class of any Target
static public function getClass( Target:* ):Class
{
return getDefinitionByName ( getQualifiedClassName( Target ) ) as Class ;
}
/// Check if object is type of Vector.< * >
static public function isVector( any:* ):Boolean
{
return String( getClass( any ) ).indexOf( "[class Vector.<" ) > -1;
}
/// Get Vector < Class >
static public function getVectorType( vector:* ):Class
{
var c:String = String( getClass( vector ) );
var s:int = c.indexOf( '<' ) + 1;
var e:int = c.indexOf( '>' );
return getDefinitionByName( c.substring( s, e ) ) as Class;
}
private function getIsVector(obj:Object):Boolean
{
return String(obj.constructor).indexOf('[class Vector.<*>]') == 0;
}