Add Elements to nullable Vector - arrays

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.

Related

Laravel Checking if Array or Collection is not Empty to run

I have an object of $person as below:
$person = Person::where('id', $id)->first();
According to which $person exists or not I load other data:
if($person) {
$person->family_members = FamilyMemberController::FamilyMemberOf($person->id);
} else {
$person->family_members = [];
}
In the view file, I check the $person->family_members if not empty and exists to add a generated value :
if(!empty(array_filter($person->family_members))) {
// my code
}
But it throws an error:
array_filter(): Argument #1 ($array) must be of type array, Illuminate\Database\Eloquent\Collection given
I need to check this $person->family_members to make sure whether it's an array or a collection is not empty.
Writing code for if array do something if collection do something is the wrong way of implementation.
You can do two things.
use both returns as collection()
or either use both returns as an array[]
If collection
else {
$person->family_members = collect();
}
If array
use ->toArray() at the end of Eloquent. Check this answer
As well, I think you are confused with array_filter(). Maybe you are searching for in_array() or contains()
Use count method
if(count($person->family_members)>0){
//your code
}
We don't know your code, but given the error, it's safe to assume your method returns a Collection. You can see available methods in the docs. However, if you need it as array, all you need to do is call ->toArray() on the result Collection. Then you can use array_filter.
What about just doing
if(!$person->family_members){
// your code here
}
or
if($person->family_members){
// your code here
} else {
// code of "if it's empty" goes here
}
You can use the count() function to return a count of an index. ex
if(count($person->family_members)){
//do your true algo
}
Why you are using the empty method ?! Try this:
$person->family_members = $person ? FamilyMemberController::FamilyMemberOf($person->id) : null;
if($person->family_members){ // your code }
Try simple ways in Programming ;)

How to access methods from array element?

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[]>.

Subclassing in Objective C Runtime

I am attempting to implement a solution from How to set canBecomeKeyWindow? Into my native C application using Objective-C runtime (The app is already written with objective C Runtime). Is there a way to create a subclass purely in Objective-C Runtime?
Right now I just create NSWindow object but need to be able to create my own so I can override the function specified in that question.
objc_msgSend((id)objc_getClass("NSWindow"), sel_registerName("alloc"));
The signature of can_become_key_window_true is slightly incorrect. According to the documentation (https://developer.apple.com/documentation/objectivec/objective-c_runtime/imp?language=objc) the function should have at least two arguments: "self" and "_cmd". So the signature should be like:
static bool can_become_key_window_true(__unused id _self, __unused SEL _cmd) {
return true;
}
You could also use #encode to construct the type encoding for the function.
char encoding[10]; // should be enough
snprintf(encoding, 10, "%s%s%s", #encode(BOOL), #encode(id), #encode(SEL));
... or you could get a method from UIWindow and get its type encoding like:
Method m = class_getInstanceMethod(objc_lookUpClass("UIWindow"), sel_getUid("canBecomeKeyWindow"));
const char *encoding = method_getTypeEncoding(m);
And as you might have noticed you could use sel_getUid() instead of sel_registerName as you expect this selector to be already registered by this time (because you are about to override an existing method).
To allocate a new instance you could use
window = class_createInstance(__UIWindow);
Figured it out after a lot of code searching:
// Subclass NSWindow with overridden function
Class __NSWindow =
objc_allocateClassPair(objc_getClass("NSWindow"), "__NSWindow", 0);
class_addMethod(__NSWindow,
sel_registerName("canBecomeKeyWindow"),
(IMP)can_become_key_window_true, "B#:");
objc_registerClassPair(__NSWindow);
// Allocate a new __NSWindow
window = objc_msgSend((id)__NSWindow, sel_registerName("alloc"));
And then can_become_key_window_true is defined as:
static bool can_become_key_window_true() {
return true;
}
I use objc_allocateClassPair to subclass the object and return a Class of that object. Then I use class_addMethod to override the method canBecomeKeyWindow. And finally use objc_registerClassPair to register my new class before using it as I would a normal NSWindow.

Access returned computed array within method and manipulate

I have a computed array which is full of tags and updates depending on what selection i make in the select box. I would like to take this array and pass it to a method and then run a method to update what “results” have an active class. Although I get an array saying I can’t run forEach on this element.
Been through a few topics and understand computed properties dont work like that but surely there is a way around this.
https://jsfiddle.net/39jb3fzw/6/
Short Snippet
methods: {
updateOutput() {
var tags = this.tagArray;
tags.forEach(function(tag) {
console.log(tag);
})
}
},
computed: {
concatenated: function () {
var ret = this.selected.concat(this.selected2, this.selected3);
this.tagArray = ret;
//this.updateOutput();
return ret;
}
}
Full Output
https://jsfiddle.net/39jb3fzw/6/
Thanks again :slight_smile:
It looks like the issue is the line:
var ret = this.selected.concat(this.selected2, this.selected3);
That line of code is returning an empty string rather than an array. This is because this.selectedX is a string rather than an Array. This explains why tag.forEach is undefined. forEach doesn't exist on the String prototype.
You can create this an array instead be doing
var ret = [ this.selected, this.selected2, this.selected3 ]
From there you can set this.tagArray to ret
Hope this helps

Kotlin: For-loop must have an iterator method - is this a bug?

I have the following code:
public fun findSomeLikeThis(): ArrayList<T>? {
val result = Db4o.objectContainer()!!.queryByExample<T>(this as T) as Collection<T>
if (result == null) return null
return ArrayList(result)
}
If I call this like:
var list : ArrayList<Person>? = p1.findSomeLikeThis()
for (p2 in list) {
p2.delete()
p2.commit()
}
It would give me the error:
For-loop range must have an 'iterator()' method
Am I missing something here?
Your ArrayList is of nullable type. So, you have to resolve this. There are several options:
for (p2 in list.orEmpty()) { ... }
or
list?.let {
for (p2 in it) {
}
}
or you can just return an empty list
public fun findSomeLikeThis(): List<T> //Do you need mutable ArrayList here?
= (Db4o.objectContainer()!!.queryByExample<T>(this as T) as Collection<T>)?.toList().orEmpty()
try
for(p2 in 0 until list.count()) {
...
...
}
I also face this problem when I loop on some thing it is not an array.
Example
fun maximum(prices: Array<Int>){
val sortedPrices = prices.sort()
for(price in sortedPrices){ // it will display for-loop range must have iterator here (because `prices.sort` don't return Unit not Array)
}
}
This is different case to this question but hope it help
This can also happen in Android when you read from shared preferences and are getting a (potentially) nullable iterable object back like StringSet. Even when you provide a default, the compiler is not able to determine that the returned value will never actually be null. The only way I've found around this is by asserting that the returned expression is not null using !! operator, like this:
val prefs = PreferenceManager.getDefaultSharedPreferences(appContext)
val searches = prefs.getStringSet("saved_searches", setOf())!!
for (search in searches){
...
}

Resources