I have the following classes and objects defined in Java
class HouseStructures
{
String roof;
String windows;
String doors;
}
HouseStructures structure1=new HouseStructures();
HouseStructures structure2 = new HouseStructures();
structure1.doors = "wood";structure1.windows="aluminium"; structure1.roof="tiles";
structure2.doors = "steel"; structure2.windows = "iron"; structure2.roof="zinc";
class Estates
{
String description;
ArrayList<HouseStructures> housestructures;
}
Estates estates = new Estates();
estates.description="fancycomplex";
estates.housestructures.add(structure1);
estates.housestructures.add(structure2);
When I get to the last couple of statements, the programme crashes and I get the error message
java.lang.NullPointerException: Attempt to invoke virtual method 'void java.util.ArrayList.add(int, java.lang.Object)' on a null object reference
How can i populate the estates.housestructure with elements. I also would like to understand why I get a null object reference when there is a fully populated object being passed as an argument.
Related
I've recently taken upon myself to add setter and getter methods to my class.
Since doing this, many parts of my code got broken and I'm unable to access getter methods.
Take the example below:
private loadInputs() : Input[] {
var inputs = <Input[]>this.get('inputs');
inputs.sort((a,b) => a.QuoteRef().localeCompare(b.QuoteRef()))
return( inputs || [] );
}
My input class has 2 variables,
_Project: string
_line: string
Which I access using a method QuoteRef()
public QuoteRef(): string {
return this._Project.concat('-' + this._Line.toString().padStart(3,'0'));
}
Whenever I try to access a method or a getter from my class on an item that is casted as an Input, I can see the variables (though not access them as they are private), but the prototype section doesn't contain any of the methods.
This triggers the following error in the website console:
TypeError: a.QuoteRef is not a function
What am I doing wrong?
Update
I got it to work by updating the code as follows:
inputs.sort((a,b) => {
let first = new Input(a);
let second = new Input(b);
return first.QuoteRef().localeCompare(second.QuoteRef());
});
Without seeing your complete class I can only guess, but I think that a and b in your sort are not of the type you expect. I can't see what this.get('inputs') does, but I suspect it is not returning an array with Input class objects. Hence the function cannot be found (is not a function). You could try:
inputs.sort((a,b) => {
console.log(typeof a);
console.log(typeof b);
a.QuoteRef().localeCompare(b.QuoteRef());
})
and check what the type is. Then check what your this.get actually returns.
Edit: forgot to mention that your IDE probably does not warn you because you cast the output of this.get to <Input[]>.
I'm passing an array of a specific model by reference between ViewControllers.
If I change any value of a specific element in the array it reflects well in all ViewControllers but when I remove an element from that array it doesn't reflect to the other controllers.
Does the remove(at: ) function create new array and refer to another address?
And if so how to delete an element without changing the address of array so it can reflect this change on the other view controllers?
Swift Arrays are value types (specifically, an array is a struct), not reference types, so you are mistaken when you say that you are "passing an array of a specific model by reference between view controllers". You can only ever pass a Swift array as a value.
Arrays, like other structs, have copy-on-modify semantics. As soon as you change the array itself a copy is made and the change is made to the copy.
Now, in your case the array contains references to model objects; When you update the model object you change the object itself, not the reference held in the array, so you see the change reflected in all of your view controllers.
An analogy might be the difference between adding a house to a street (which changes the street itself) versus changing the occupants of an existing house on the street.
I would suggest you implement a model object that provides abstraction from the underlying array so that you have better code and avoid the issue with array references.
One approach could be something like:
struct MyModel {
let name: String
let size: Int
}
class MyData {
private var _models = [MyModel]()
var models: [MyModel] {
return _models
}
func insert(model: MyModel) {
self._models.append(model)
}
func removeModel(at: Int) {
guard at >= 0 && at < _models.count else {
return
}
self._models.remove(at: at)
}
}
Although this isn't ideal as it still requires model consumers to know indices in the underlying array. I would prefer something like this:
struct MyModel: Hashable {
let name: String
let size: Int
}
class MyData {
private var _models = [MyModel]()
var models: [MyModel] {
return _models
}
func insert(model: MyModel) {
self._models.append(model)
}
func remove(model: MyModel) -> Bool {
if let index = self._models.index(of: model) {
_models.remove(at: index)
return true
} else {
return false
}
}
}
Now I don't need to know what internal collection MyData uses to store the models.
If you need to pass an array (or any other value type) by reference, you could go through an intermediate structure that manages the indirection for you.
[EDIT] changed to use KeyPaths available in Swift 4.
// Generic class to hold a "weak" reference to a property from an object
// including properties that are valued types such as arrays, structs, etc.
// This is merely an encapsulation of Swift's native KeyPath feature
// to make the code a bit more readable and simpler to use
//
class ReferenceTo<ValueType> { var value:ValueType! { get { return nil} set {} } }
class Reference<OwnerType:AnyObject,ValueType>:ReferenceTo<ValueType>
{
internal weak var owner:OwnerType!
internal var property:ReferenceWritableKeyPath<OwnerType,ValueType>! = nil
internal var valueRef:KeyPath<OwnerType,ValueType>! = nil
init(_ owner:OwnerType, _ property:ReferenceWritableKeyPath<OwnerType,ValueType>)
{ (self.owner,self.property) = (owner,property) }
init(_ owner:OwnerType, get valueRef:KeyPath<OwnerType,ValueType>)
{ (self.owner,self.valueRef) = (owner,valueRef) }
override var value:ValueType!
{
get { return valueRef != nil ? owner?[keyPath:valueRef] : owner?[keyPath:property] }
set { owner?[keyPath:property] = newValue }
}
}
With this generic class you can create references to valued type properties of object instances and manipulate them anywhere in your code as if the valued type property was a reference type.
// Example class with a read/write and a read-only property:
class MyObject
{
var myArray = [1,2,3,4]
var total:Int { return myArray.reduce(0,+) }
}
var instance:MyObject! = MyObject()
// create a reference to the array (valued type)
// that can be used anywhere and passed around as a parameter
let arrayRef = Reference(instance, \.myArray)
// the value is accessed and manipulated using the
// "value" property of the reference
arrayRef.value.remove(at:2)
arrayRef.value.append(5)
print(instance.myArray) // [1,2,4,5]
// Read-only properties can also be manipulated as
// references
let valueRef = Reference(instance, get:\.total)
print(valueRef.value) // 12
The Reference class allows passing the value as a reference to function parameters
// a function that expects a reference to an array
// would be declared as follows
func changeArray(_ array:ReferenceTo<[Int]>)
{ array.value.insert(9, at: 1) }
// the reference can also be used as an inout parameter
func shift(_ array:inout [Int])
{ array = Array(array.dropFirst()) + Array(array.prefix(1)) }
changeArray(arrayRef)
shift(&arrayRef.value!)
print(instance.myArray) // [9,2,4,5,1]
...
// the reference uses a weak link to the owner
// of the referenced property or value
// so there will be no strong reference cycle issues even
// if the reference is used in an object held strongly
// by the owner itself
instance = nil
print(arrayRef.value) // none ... no more value after the owner is gone
Alright, so I got a private ?Vector $lines which is empty when constructing the object and now I want to add strings to that Vector. The following Hack code works well:
<?hh
class LineList {
private ?Vector<string> $lines;
public function addLine(string $line): void {
$this->file[] = trim($line);
}
}
But when checking the code with hh_client, it gives me the following warning:
$this->file[]]: a nullable type does not allow array append (Typing[4006])
[private ?Vector<string> $lines]: You might want to check this out
Question: How do I add elements to the Vector without that the checker pushs this warning?
The easiest way would be to not use a nullable Vector. private Vector<string> $lines = Vector {}; gets around the need for a constructor too.
Otherwise, you'll need to check if the value isn't null, then append to it:
public function addLine(string $line): void {
$vec = $this->lines;
if ($vec !== null) $vec[] = trim($line);
}
You can't just check if $this->lines !== null as it is possible for it to change value between checking and appending (with something like a tick function), hence why it is assigned to a local variable instead.
I'm writing a method to output to several output streams at once, the way I got it set up right now is that I have a LogController, LogFile and LogConsole, the latter two are implementations of the Log interface.
What I'm trying to do right now adding a method to the LogController that attaches any implementation of the Log interface.
How I want to do this is as follows: in the LogController I have an associative array, in which I store pointers to Log objects. When the writeOut method of the LogController is called, I want it to then run over the elements of the array and call their writeOut methods too. The latter I can do, but the previous is proving to be difficult.
Mage/Utility/LogController.d
module Mage.Utility.LogController;
import std.stdio;
interface Log {
public void writeOut(string s);
}
class LogController {
private Log*[string] m_Logs;
public this() {
}
public void attach(string name, ref Log l) {
foreach (string key; m_Logs.keys) {
if (name is key) return;
}
m_Logs[name] = &l;
}
public void writeOut(string s) {
foreach (Log* log; m_Logs) {
log.writeOut(s);
}
}
}
Mage/Utility/LogFile.d
module Mage.Utility.LogFile;
import std.stdio;
import std.datetime;
import Mage.Utility.LogController;
class LogFile : Log {
private File fp;
private string path;
public this(string path) {
this.fp = File(path, "a+");
this.path = path;
}
public void writeOut(string s) {
this.fp.writefln("[%s] %s", this.timestamp(), s);
}
private string timestamp() {
return Clock.currTime().toISOExtString();
}
}
I've already tried multiple things with the attach functions, and none of them. The build fails with the following error:
Mage\Root.d(0,0): Error: function Mage.Utility.LogController.LogController.attach (string name, ref Log l) is not callable using argument types (string, LogFile)
This is the incriminating function:
public void initialise(string logfile = DEFAULT_LOG_FILENAME) {
m_Log = new LogController();
LogFile lf = new LogFile(logfile);
m_Log.attach("Log File", lf);
}
Can anyone tell me where I'm going wrong here? I'm stumped and I haven't been able to find the answer anywhere. I've tried a multitude of different solutions and none of them work.
Classes and interfaces in D are reference types, so Log* is redundant - remove the *. Similarly, there is no need to use ref in ref Log l - that's like taking a pointer by reference in C++.
This is the cause of the error message you posted - variables passed by reference must match in type exactly. Removing the ref should solve the error.
I have a function that handles two types: NVector and NMatrix; the former is derived from the latter. This function is basically a specialized copy constructor. I want it to return an object of the same type as that upon which it was called, so, NVector returns NVector, not NMatrix.
static VALUE nm_init_modifiedcopy(VALUE self) {
// ... some code ...
// formerly, I had cNMatrix where klass is. But it could also be cNVector!
return Data_Wrap_Struct(klass, mark_func, delete_func, unwrapped_self_copy);
}
How do I get the class property of an object to pass into Data_Wrap_Struct?
Like clockwork, as soon as I ask a question on Stackoverflow, I find the answer.
The macro is CLASS_OF.
static VALUE nm_init_modifiedcopy(VALUE self) {
// ... some code ...
return Data_Wrap_Struct(CLASS_OF(self), mark_func, delete_func, unwrapped_self_copy);
}