AS3 - Private Object. Make property as read only - class

I have a object property in my Class which is private and marked as read-only.
private var readOnlyObj:Object;
I can only access it with a get method:
public function get readOnly(){ return readOnlyObj }
I can access it by:
var objClass = new MyClass();
trace(objClass.readOnly)
And if i'll try to modify it:
objClass.readOnly = new Object();
I'll get an error:
Error# Property is read only.
Now my question is:
How do I set the properties of my readOnlyObj as read-only?
If I have set the object in the constructor:
readOnlyObj["property1"] = 0;
And modify that property by:
objClass.readOnly["property1"] = 2;
It is valid. I want set the property1 to a read-only property. Is this possible? Thank You!

You can do this by returning a duplicate of the original object and not the object itself.
The transform properties of DisplayObjects work like this: you can get the object property from a get function and can modify the object, but such modification has no effect until you pass the modified object back to the set function.
In your case, there's no way to give the object back (no setter) and by returning a copy (commonly called 'clone') from the getter, there is no way to modify the object property from outside, because the returned reference reference the newly created independent clone, essentially making the internal object constant.

What you are asking is not possible and only yield the answer "no" if on the other hand you asked about how to achieve that functionality then there would be a few answer possible.
First of all given your code and the problem at hand it is clear that you misunderstand the class scope. You set:
private var readOnlyObj:Object;
As read only while it's really not the object you want to protect, it's its properties. So readOnlyObj should really not even be visible and accessible.
Now that readOnlyObj is private and not accessible, you can put together a simple method to retrieve properties:
public function getProperty(name:String):*
{
if(readOnlyObj[name] != undefined)
{
return readOnlyObj[name];
}
return null;
}
It might also be useful to know how to put together a public setter that cannot be used externally.
Create an internal Boolean variable (only with true package), then internally set that variable to true before setting the property then set it back to false. Since externally that boolean cannot be set you end up with a public setter that cannot be used externally.
internal var allowSetter:Boolean;
public function set whatever(value:*):void
{
if(allowSetter)
{
//set property ect...
allowSetter = false;
}
}

You can't really do this, at least in the way you describe. You can of course make your readOnly object a custom class instance that only has read-only properties, but you can't freeze a dynamic Object instance.

Related

Hiding property setters by class in Swift

I would like to hide some property setters and initializers on my Swift model objects. These are reference data that the server provides, and under no circumstances should they be created or modified by the application. This is simple enough in Swift.
However, there is application in my project (a separate target) that needs to break this rule. It is a tool I use to populate the data in bulk, so of course needs to be able to initialize new model objects and set their properties.
What are my options for accomplishing this? I would rather not use a completely new project since it will mean a lot of code duplication. Is there some language-level way to keep this mutability hidden from one application but available to another?
If you declare a property with the let keyword. It can then only be set in the init of the type.
You can also declare a private setter to make the property readonly from the caller of the type but read/write inside the type
struct Foo {
private(set) var bar: Bool = true
func toggle() {
bar.toggle()
}
}
var foo = Foo()
let barState = foo.bar // This works
foo.toggle() // This works too
foo.bar.toggle() // This will make a compile time error

Setter for Bool in Swift

I'm using a custom getter like so
var currentShowLiked: Bool {
get {
return [some condition met] ? true : false
}
set {
self.currentShowLiked = newValue
}
}
and it works fine. However, I would expect to be able to set true or false value back to my variable, but Swift forced my to implement a setter, which does not produce any warnings, but at runtime if I'm to change value of my variable, app crashes with no apparent reason or sane explanation pointing to setter line with EXC_BAD_ACCESS (code=2...) and a message in console warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
Why do I do?
You are in recursive context.
You can't use currentShowLiked in the currentShowLiked property body as below:
// Recursive, Infinite loop
self.currentShowLiked = newValue
To fix this:
private var _currentShowLiked : Bool
var currentShowLiked: Bool {
get {
return [ some condition met on _currentShowLiked ] ? true : false
}
set {
self._currentShowLiked = newValue
}
}
A Swift property that defines a custom getter and / or setter operation is a computed property which does not actually stores a value. The custom setter can be used to modify the internal state of other properties.
See also: "The Swift Programming Language" page 180
You can not set value in its setter because you are creating a recursion -method calling itself because:
self.currentShowLiked = newValue
will call set method you defined which will go and go. If you are overriding setter and getter you probably want to have some backing store property which will be private.
Moreover you defined a getter which base on some condition so anyway you are not using the value you set on this property. I think you do not need this set
The error here is caused by a misunderstanding.
When you declare a
var a:Type
A member value a is allocated inside the object, and accessors and mutators are automatically created to allow you to read and write that variable.
However, when you declare
var a:Type { get { ... } set { ... } }
No member value is allocated - you have indicated that when the value is accessed (read) or mutated (written) from a user of the object, your code will do all necessary action to respond to it. If you ultimately want the value to be stored, you will need to store it to an actual value, (which will need a different name).
Since you are invoking the mutator of the object inside the mutator of the object, you have set up an infinite loop, which causes your program to crash due to stack overflow (all function call memory is used to store the record of the function calling itself over and over again).
The code you have above will crash because it causes an infinite loop - your setter for currentShowLiked sets currentShowLiked to the new value, so then that calls the setter again, and so on.
You don't have to implement a setter, but you then don't use get - the syntax is like this:
var currentShowLiked: Bool {
return [some condition met]
}

Restangular extendModel on new object

Restangular offers a feature, extendModel, which lets you add functionality onto objects returned from the server. Is there any way to get these methods added to an empty / new model, that hasn't yet been saved to the server?
I wanted to do the same thing but didn't find an example. Here's how I ended up doing it:
models.factory('User', function(Restangular) {
var route = 'users';
var init = {a:1, b:2}; // custom User properties
Restangular.extendModel(route, function(model) {
// User functions
model.myfunc = function() {...}
return model;
});
var User = Restangular.all(route);
User.create = function(obj) {
// init provides default values which will be overridden by obj
return Restangular.restangularizeElement(null, _.merge({}, init, obj), route);
}
return User;
}
Some things to be aware of:
Use a function like _.merge() instead of angular.extend() because it clones the init variable rather than simply assigning its properties.
There is a known issue with Restangular 1.x that causes the Element's bound data to not be updated when you modify its properties (see #367 and related). The workaround is to call restangularizeElement() again before calling save(). However this call will always set fromServer to false which causes a POST to be sent so I wrote a wrapper function that checks if id is non-null and sets fromServer to true.

Access class property from instance?

I am not sure is this is correct behaviour or if its unintended. I have setup StealthFighter so that it returns a class type computed property variable called ammunition.
func globalTests() {
println("globalTests")
println("AMMUNITION: \(StealthFighter.ammunition)")
var myStealthFighter = StealthFighter()
println("MISSILES: \(myStealthFighter.missiles)")
println("AMMUNITION: \(myStealthFighter.ammunition)") // ERROR
}
class StealthFighter {
class var ammunition:Int {
return 500;
}
var missiles: Int = 5
}
When directly accessing the class StealthFighter this works fine and returns 500 as expected. But if I create and instance myStealthFighter and then try and access the class property on the instance I get the error: 'StealthFighter' does not have a member named 'ammunition' I can't find any mention of this, I am assuming from this that class properties are accessible only via the class? and not on any instances created from it? I just want to make sure I am understanding this correctly ...
EDIT:
So I have probably worded the type variable name wrong as it should probably be maxAmmunition to signify that StealthFighters can only take 500 rounds. I can see the point, if you want the maxAmmunition for the class then you ask the class.
As #Kreiri and #0x7fffffff points out it does seem that you can ask the instance what the class ammunition (or maxAmmunition) is by using dynamicType.
println("CLASS - AMMUNITION: \(StealthFighter.ammunition)")
var myStealthFighter = StealthFighter()
println("INSTA - AMMUNITION: \(myStealthFighter.dynamicType.ammunition)")
.
// OUTPUT
// CLASS - AMMUNITION: 500
// INSTA - AMMUNITION: 500
Your assumption is correct. Type variables are only meant to be accessed directly from the class. If you want to get at them from an instance, you can do so by accessing the dynamicType property on your instance, like so.
let theFighter = StealthFighter()
let missiles = theFighter.dynamicType.missiles
println(missiles)
However, I don't think that this is the correct approach for you to be taking here. Assuming that you want to have one class "StealthFighter", and possibly multiple instances of that class, each with the ability to have its own number of missiles independent of the others, you should probably make this an instance variable by simply ditching the class keyword.
dynamicType allows access instance’s runtime type as a value, so accessing class property from instance would look like this:
var myStealthFighter = StealthFighter()
myStealthFighter.dynamicType.ammunition
Works in playground, at least.
These properties are known as Type properties in swift. It should be called on its type ie class name, not on instance. Type properties holds same value across all the instances of the class just like static constant in C.
Querying and Setting Type Properties
Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on the type, not on an instance of that type
Excerpt from : swift programming language
Swift 4:
var myStealthFighter = StealthFighter()
type(of: myStealthFighter).ammunition
Yes. This is a correct behaviour. These Type Properties can only be accessed over the Type and are not available on the instance itself.
In the Swift Book from Apple it is described in the section "Type Properties" (Page 205).
Swift Type Properties
“Unlike stored instance properties, you must always give stored type properties a default value. This is because the type itself does not have an initializer that can assign a value to a stored type property at initialization time"

Change G_PARAM_CONSTRUCT_ONLY property via inheritance

I try to inherit a gobject and, among other things, would like to change the value of a G_PARAM_CONSTRUCT_ONLY property so the next child class doesn't have to care.
Here's an example to depict this: GtkComboBox has a construct only property called "has-entry" with default value FALSE. In class A I want to change this value to TRUE, so that class B doesn't need to care.
GtkComboBoxClass <-- AClass <-- BClass
"has-entry" FALSE TRUE
The first naive approach was to use g_object_set() in A's instance_init function, but to no avail.
The next idea was to obtain the GParamSpec with g_object_class_find_property() and change the default value with g_param_value_set_default() in A's class_init function. But I suppose this to change the default for all GtkComboBoxClass derived objects.
The best idea I could come up with: If g_object_class_override_property() creates a new GParamSpec I could find this and set its default value in A's class_init function. But documentation doesn't loose a word about this.
So my question: Is this a working, and intended, way of accomplishing this, or is there a better solution?
Tried so far:
g_object_set() in instance init():
no warning on start
no effect
g_object_set() in GObjectClass->constructor():
no warning on start
no effect
warning on exit: invalid cast from GtkCellCiew to GtkEntry
g_object_set() in GObjectClass->constructed():
warning on start: can't be set after construction
Thanks
Stefan
if you want to set a property in a sub-class, and that property is construct-only, then you should use the constructed virtual function to call g_object_set() instead of the init virtual.
properties marked as construct-only will be applied during construction, using their default value, unless specified on the constructor itself — i.e. with g_object_new(). this means that setting a construct-only property inside init() will not suffice, as the value will be set after init() has been called. the constructed() virtual function, on the other hand, is called after the constructor properties have been applied, so it's possible to override the default value there.
Answering this for myself:
A look into gobject source reveals that the properties list given to constructor() contains all G_PARAM_CONSTRUCT and G_PARAM_CONSTRUCT_ONLY properties and their default or given values.
Modifying these values is undocumented (or at least I couldn't find it), but it works.
Construction time property values have to be modified in this list before chaining up to parents constructor, non construct properties have to be set afterwards. Example code looks like:
static GObject *constructor(GType gtype, guint n_properties, GObjectConstructParam *properties) {
GObject *object;
guint i;
gchar const *name;
GObjectConstructParam *property;
for (i = 0, property = properties; i < n_properties; ++i, ++property) {
name = g_param_spec_get_name(property->pspec);
if (!strcmp(name, "has-entry")) // is G_PARAM_CONSTRUCT_ONLY
g_value_set_boolean(property->value, TRUE);
}
object = G_OBJECT_CLASS(parent_class)->constructor(gtype, n_properties, properties);
g_object_set(object, "entry-text-column", TEXT_COLUMN, NULL);
return object;
}