I'm developing an iphone application and when I compile it I receive some warnings. The application works, but probably it is interesting to delete all the warnings no?
This is one of them, that I can't undersand, basically because I'm a "rookie" with iPhone SDK and this class comes from another code (free code).
The warning are:
warning: implicit declaration of function 'NSAllocateCollectable'
warning: initialization makes pointer from integer without a cast
The code is this:
double *MatrixAllocateArray( NSUInteger rows, NSUInteger columns )
{
// Allocate an array to hold [rows][columns] matrix values
NSCParameterAssert(rows!=0);
NSCParameterAssert(columns!=0);
__strong double *array = NSAllocateCollectable(SIZEOFARRAY(rows,columns),0); //(WARNINGS APPEAR HERE)
NSCAssert2(array!=NULL,#"falled to allocate %dx%d matrix",rows,columns);
return array;
}
As you can see this function try to allocate a matrix, and it is called by another function.
double *MatrixAllocateEmptyArray( NSUInteger rows, NSUInteger columns )
{
// Allocate a matrix array and fill it with zeros
__strong double *emptyArray = MatrixAllocateArray(rows,columns);
bzero(emptyArray,SIZEOFARRAY(rows,columns));
return emptyArray;
}
And this is called by the function which I execute and need:
- (id)initWithRows:(NSUInteger)rowCount columns:(NSUInteger)colCount
{
// Create an empty matrix
return [self initWithAllocatedArray:MatrixAllocateEmptyArray(rowCount,colCount)
rows:rowCount
columns:colCount];
}
There's no garbage collector for iPhone programs. Allocating collectable memory is pretty much meaningless in that sitaution, so you're probably out of luck. You should probably fix your program and/or framework to use the traditional Objective-C memory management practices. The reasons for your specific warnings:
implicit declaration of function 'NSAllocateCollectable'
There is no declaration of NSAllocateCollectable for your iPhone app, so the compiler is going to fall back to the default C rules for implicit function declarations, meaning it will assume it returns int.
initialization makes pointer from integer without a cast
Because of the previous problem with the implicit declaration, your code looks to the compiler like it is trying to assign an int to a variable of type double * - implicit conversions from integer types to pointers are a cause for warnings.
Related
From the docs:
Note: HHVM allows syntax such as $x = Vector<int>{5,10};, but Hack
disallows the syntax in this situation, instead opting to infer
it.
Is there a specific reason for this? Isn't this a violation of the fail-fast rule?
There are some situations in which this would cause error to be deffered, which in turn leads to harder backtracing.
For example:
<?hh // strict
function main() : void {
$myVector = new Vector([]); // no generic syntax
$myVector->addAll(require 'some_external_source.php');
}
The above code causes no errors until it is used in a context where the statically-typed collection is actually in place:
class Foo
{
public ?Vector<int> $v;
}
$f = new Foo();
$f->v = $myVector;
Now there is an error if the vector contains something else then int. But one must trace back the error to the point where the flawed data was actually imported. This would not be necessary if one could instantiate the vector using generic syntax in the first place:
$myVector = new Vector<int>([]);
$myVector->addAll(require 'some_external_source.php'); // fail immediately
I work on the Hack type system and typechecker at Facebook. This question has been asked a few times internally at FB, and it's good to have a nice, externally-visible place to have an answer to it written down.
So first of all, your question is premised on the following code:
<?hh // strict
function main() : void {
$myVector = new Vector([]); // no generic syntax
$myVector->addAll(require 'some_external_source.php');
}
However, that code does not pass the typechecker due to the usage of require outside toplevel, and so any result of actually executing it on HHVM is undefined behavior, rendering this whole discussion moot for that code.
But it's still a legitimate question for other potential pieces of code that do actually typecheck, so let me go ahead and actually answer it. :)
The reason that it's unsupported is because the typechecker is actually able to infer the generic correctly, unlike many other languages, and so we made the judgement call that the syntax would get in the way, and decided to disallow it. It turns out that if you just don't worry about, we'll infer it right, and still give useful type errors. You can certainly come up with contrived code that doesn't "fail fast" in the way you want, but it's, well, contrived. Take for example this fixup of your example:
<?hh // strict
function main(): void {
$myVector = Vector {}; // I intend this to be a Vector<int>
$myVector[] = 0;
$myVector[] = 'oops'; // Oops! Now it's inferred to be a Vector<mixed>
}
You might argue that this is bad, because you intended to have a Vector<int> but actually have a Vector<mixed> with no type error; you would have liked to be able to express this when creating it, so that adding 'oops' into it would cause such an error.. But there is no type error only because you never actually tried to use $myVector! If you tried to pull out any of its values, or return it from the function, you'd get some sort of type compatibility error. For example:
<?hh // strict
function main(): Vector<int> {
$myVector = Vector {}; // I intend this to be a Vector<int>
$myVector[] = 0;
$myVector[] = 'oops'; // Oops! Now it's inferred to be a Vector<mixed>
return $myVector; // Type error!
}
The return statement will cause a type error, saying that the 'oops' is a string, incompatible with the int return type annotation -- exactly what you wanted. So the inference is good, it works, and you don't ever actually need to explicitly annotate the type of locals.
But why shouldn't you be able to if you really want? Because annotating only generics when instantiating new objects isn't really the right feature here. The core of what you're getting at with "but occasionally I really want to annotate Vector<int> {}" is actually "but occasionally I really want to annotate locals". So the right language feature is not to let you write $x = Vector<int> {}; but let you explicitly declare variables and write Vector<int> $x = Vector {}; -- which also allows things like int $x = 42;. Adding explicit variable declarations to the language is a much more general, reasonable addition than just annotating generics at object instantiation. (It's however not a feature being actively worked on, nor can I see it being such in the near to medium term future, so don't get your hopes up now. But leaving the option open is why we made this decision.)
Furthermore, allowing either of these syntaxes would be actively misleading at this point in time. Generics are only enforced by the static typechecker and are erased by the runtime. This means that if you get untyped values from PHP or Hack partial mode code, the runtime cannot possibly check the real type of the generic. Noting that untyped values are "trust the programmer" and so you can do anything with them in the static typechecker too, consider the following code, which includes the hypothetical syntax you propose:
<?hh // partial
function get_foo() /* unannotated */ {
return 'not an int';
}
<?hh // strict
function f(): void {
$v = Vector<int> {};
$v[] = 1; // OK
// $v[] = 'whoops'; // Error since explicitly annotated as Vector<int>
// No error from static typechecker since get_foo is unannotated
// No error from runtime since generics are erased
$v[] = get_foo();
}
Of course, you can't have unannotated values in 100% strict mode code, but we have to think about how it interacts with all potential usages, including untyped code in partial mode or even PHP.
I have an instance variable which is a struct, for example:
struct Data {
UInt32 i;
UInt32 arr[1];
};
And a property is defined in my class:
#property struct Data data; // and the corresponding #synthesize in the imp file
Now, I am aware that changing the values of i and arr through the getter of data is conceptually wrong, since I will be accessing the copy of data returned by the getter (the correct way is accessing it using self->data).
However some general Objective-C questions arise regarding the following lines:
self.data.i = 1; // produces compile error
self.data.arr[0] = 1; // compiles ok
First, why does the first line produces a compile error, and the 2nd line does not?
Second, if the dot syntax in the above line (self.data) is just a syntactic sugar to [self data], why do I get 2 different (although similar) compile errors?
self.data.i = 1; // error: Expression is not assignable
[self data].i = 1; // error: Semantic Issue: Assigning to 'readonly' return result of an objective-c message not allowed
Actually, structs are passed by value in C (and Objective C). That means that your property actually returns a read only copy (rvalue) of the internal "Data" type. The assignment is to the temporary returned copy, which the compiler (rightfully) flags as a bit suspect.
The second line that compiles correctly does so since self.data.arr returns a read only UInt32*, but when you index it with [0] and write to that, you're not writing to the pointer, you're writing to the memory that it points to which is allowed.
Hello
I am trying to make this function to return an array! What is going wrong here?
-(char[10])print01:(int)int11{ //error: declared as method returning an array
char arrayT[10];
for(int i=0;i<8;i++)
{
if ((int1-n1)>=0){
arrayT[i]='1';
int1-=n1;
}
else
arrayT[i]= '0';
n1=n1/2;
}
return arrayT[]; // incompatible types in return
}
and I want to call it like that:
char array1[10] = [self print01:(int)int1]; //error: invalid initializer
any suggestions please?
You can't return an array in C or in Objective-C. The best you can hope for is to return a pointer to an array, but if you're going to do that, make sure you don't return a pointer to an array on the stack (like yours is).
The best approach is using an NSArray (of objects of course, I'm assuming the above code is simplified sample, but you can always use an NSNumber). Alternatively, you could return a pointer to an array, which is common in C as C (and objective c by extension) cannot return an array. Unfortunately, this would require allocating memory for the array and using manual memory management, (malloc/free) which depending on the lifecycle of the array, can be anywhere from a nuisance to awful. My recommendation is taking a char *dest parameter, and inserting chars into the array as dest[i]
Hi I am trying to init an object with a double value in the format double filter[3][3];
but i keep getting the following error.
cannot convert 'double[3][3]' to 'double' in assignment.
in my header i have this
#interface filter : NSObject
{
double **matrix;
}
#property(nonatomic)double **matrix;
-(id)initWithMatrix:(double**)filterMatrix;
inside my class i have this method.
-(id)initWithMatrix:(double**)filterMatrix
{
matrix = filterMatrix;
return self;
}
and i am trying to call it like this.
double filter[3][3] = {0,0,0,0,1,0,0,0,0};
MyMatrix *myMatrix = [[MyMatrix alloc] initWithMatrix:filter];
I now get the error.
Error: Cannot convert double[*][3] to double** in argument passing
Any help on this issue would be amazing.
Thanks
A
That's because double** isn't the equivalent of double[*][*]. In fact, double[*][*] is an invalid type, because it leaves the stride undefined. double** is a pointer to a pointer to a double, or to put it another way, it's a pointer to an array of doubles. You should just use double* as your type.
Edit: To clarify, double[*][3] is still just an array of doubles, even though it has 2 dimensions. This is still the equivalent of double*.
A two-dimensional array is not the same thing as a pointer-to-a-pointer. You have two choices - change the filter class to contain a 2D array, or change your initialization to use pointer-to-pointers.
In choice #1, you're could keep a copy of the array in your filter instance, instead of just holding a pointer. You need to change the class interface:
#interface filter : NSObject
{
double matrix[3][3];
}
-(id)initWithMatrix:(double[3][3])filterMatrix;
Then your implementation of initWithMatrix: can just do a memcpy() or the equivalent to copy the data into your instance.
Choice #2 is a bit different. Keep your other code the way it is, but change your initialization of filter:
double row0[3] = {0,0,0};
double row1[3] = {0,1,0};
double row2[3] = {0,0,0};
double **filter[3] = { row0, row1, row2 };
It's probably safer to malloc() all of those arrays, since otherwise you're going to end up with references to stack variables in your filter class, but I think you get the idea.
you are passing as a parameter a double 2d array(double[][]) when your method signature asks for a double (a primitive like 34.2).
set the method declaration to
- (id)initWithMatrix:(double*) matrix;
this passes a pointer to your array (2d) to the method.
edit: missed a semicolon.
Hi I am trying to init an object with a double value in the format double filter[3][3];
but i keep getting the following error.
cannot convert 'double[3][3]' to 'double' in assignment.
in my header i have this
#interface filter : NSObject
{
double **matrix;
}
#property(nonatomic)double **matrix;
-(id)initWithMatrix:(double**)filterMatrix;
inside my class i have this method.
-(id)initWithMatrix:(double**)filterMatrix
{
matrix = filterMatrix;
return self;
}
and i am trying to call it like this.
double filter[3][3] = {0,0,0,0,1,0,0,0,0};
MyMatrix *myMatrix = [[MyMatrix alloc] initWithMatrix:filter];
I now get the error.
Error: Cannot convert double[*][3] to double** in argument passing
Any help on this issue would be amazing.
Thanks
A
That's because double** isn't the equivalent of double[*][*]. In fact, double[*][*] is an invalid type, because it leaves the stride undefined. double** is a pointer to a pointer to a double, or to put it another way, it's a pointer to an array of doubles. You should just use double* as your type.
Edit: To clarify, double[*][3] is still just an array of doubles, even though it has 2 dimensions. This is still the equivalent of double*.
A two-dimensional array is not the same thing as a pointer-to-a-pointer. You have two choices - change the filter class to contain a 2D array, or change your initialization to use pointer-to-pointers.
In choice #1, you're could keep a copy of the array in your filter instance, instead of just holding a pointer. You need to change the class interface:
#interface filter : NSObject
{
double matrix[3][3];
}
-(id)initWithMatrix:(double[3][3])filterMatrix;
Then your implementation of initWithMatrix: can just do a memcpy() or the equivalent to copy the data into your instance.
Choice #2 is a bit different. Keep your other code the way it is, but change your initialization of filter:
double row0[3] = {0,0,0};
double row1[3] = {0,1,0};
double row2[3] = {0,0,0};
double **filter[3] = { row0, row1, row2 };
It's probably safer to malloc() all of those arrays, since otherwise you're going to end up with references to stack variables in your filter class, but I think you get the idea.
you are passing as a parameter a double 2d array(double[][]) when your method signature asks for a double (a primitive like 34.2).
set the method declaration to
- (id)initWithMatrix:(double*) matrix;
this passes a pointer to your array (2d) to the method.
edit: missed a semicolon.