In my iOS application I want to define two block types that take each other as parameters:
typedef void (^BlockA)(BlockB b);
typedef void (^BlockB)(BlockA a);
This fails compilation with 'Unknown type name BlockB in the first typedef (that makes sense).
I have a workaround which defines the types like this:
typedef void (^BlockA)(id);
typedef void (^BlockB)(BlockA a);
I then cast back to the BlockB type inside the BlockA definition, but at the expense of type safety.
I also looked at not using typedefs, but this results in an infinite nesting of expanded block definitions.
I know how to resolve circular dependencies for structs with forward declarations, but I can't see how to do this with blocks.
If there is no solution to the circular dependency, is there a way that I can restrict the parameter to BlockA to be any Block type rather than the generic id, this would give some level of type safety.
typedef does not define a "real" type. It's basically like a macro that expands out everywhere it's used. That's why typedefs cannot be recursive.
Another way to think about it is, typedefs are never necessary -- you can always take any piece of code with a typedef, and simply replace every occurrence of it with the underlying type (that's what the compiler does when you compile), and it will always work and be completely equivalent. Think about it -- how would you do it without a typedef? You can't. So you can't do it with a typedef either.
The only ways to do it are: use id as the argument type to erase the type like you're doing; or, encapsulate the block inside a "real" type like a struct or class. However, if you do it the latter way, you have to explicitly put the block into and extract the block out of the struct or class, which makes the code confusing. Also, struct is dangerous as struct is a scalar C type, and if you need to capture it by a block, it doesn't automatically memory-manage the objects inside the struct. As for class, defining a wrapping class is very verbose, and using it for this causes the allocation of an extraneous dummy object for every block it wraps.
In my opinion, using id like you're using is fine and is the cleanest way. However, keep in mind that if you need to have that block passed as id be captured by another inner block, that you should cast it back to the block type before being captured, as the capturing semantics is different for block and other object types (blocks are copied, whereas other objects are retained). Just casting it back to the block type at the earliest place will work.
Related
I need to implement an abstract class function, which own a an specific data type. But I need inside my logic layer to make the attribute which is going to be passed as a dynamic data type. But when i Pass it to the function, i am sure that its data type will be as needed. So, i type (product.value.pickedImages) as ListOf5) . But it does an Exception.
The Abstract Class Code Is:
Future<Either<FireStoreServerFailures, List<String>>> uploadProductImages(
{required ListOf5<File> images});
The Implementation Code Is:
Future<Option<List<String>>> _uploadImagesToFirestorage() async {
return await productRepo
.uploadProductImages(
images: (product.value.pickedImages) as ListOf5<File>) // Exception
}
The Exception Is:
The argument type 'ListOf5 < dynamic>' can't be assigned to the
parameter type 'ListOf5 < File>'.
You are trying to cast the List from List<dynamic> to List<String>.
Instead, you should cast each item, using something like this:
void main() {
List<dynamic> a = ['qwerty'];
print(List<String>.from(a));
}
Not sure about the implementation of this ListOf5 though...
The cast (product.value.pickedImages) as ListOf5<File> fails.
It fails because product.value.pickedImages is-not-a ListOf5<File>, but instead of ListOf5<dynamic> (which may or may not currently contain only File objects, but that's not what's being checked).
Unlike a language like Java, Dart retains the type arguments at run-time(it doesn't do "erasure"), so a ListOf5<dynamic> which contains only File objects is really different from a ListOf5<File> at run-time.
You need to convert the ListOf5<dynamic> to a ListOf5<File>.
How to do that depends on the type ListOf5, which I don't know.
For a normal List, the two most common options are:
(product.value.pickedImages).cast<File>(). Wraps the existing list and checks on each read that you really do read a File. It throws if you ever read a non-File from the original list. Perfectly fine if you'll only read the list once.
List<File>.of(product.value.pickedImages). Creates a new List<File> containing the values of product.value.pickedImages, and throws if any of the values are not File objects. Requires more memory (because it copies the list), but fails early in case there is a problem, and for small lists, the overhead is unlikely to be significant. If you read the resulting list many times, it'll probably be more efficient overall.
If the ListOf5 class provides similar options, you can use those. If not, you might have to build a new ListOf5 manually, casting each element of the existing ListOf5<dynamic> yourself.
(If the ListOf5 class is your own, you can choose to add such functionality to the class).
I need a modifiable collection like a List or a Set to be passed as a parameter. Using Iterable doesn't guarantee this argument to have methods like add or remove.
Example method:
void foo(Iterable bar) {
bar.add(); // The method 'add' isn't defined for the type 'Iterable'.
}
Is there a class / interface for (modifiable) collections which guarantees those methods? If not, why?
There is not a modifiable type. Very early (before Dart 1) we had some other types in our hierarchy, but we decided to avoid including them because things were getting a bit too complex.
I still wish we'd shipped a List interface without the mutation members. 🤷
C# discards prevent allocation of values not needed. Is there something similar in dart? I saw a lot of people use the underscore as if it were a discard, but using two at the same time (like this (_, _) => method() will say the variable _ is already defined.
Dart does allow you to use the same discard operator as C#. You can define a variable or final with a name of _. This works well with the rule avoid-ignoring-return-values (Dart Code Metrics) Importantly, if you name the variable with this, you will not encounter the warning unused-local-variable. However, there is another code rule called no_leading_underscores_for_local_identifiers. You can safely turn this off as long as you don't have someone in your team that has a habit of prefixing variable names with an underscore.
Ignoring the return value
Discarding the return variable
Unfortunately, it doesn't work the same way as C# because it involves an assignment, and you cannot assign two different types to it. You need to declare it as an Object?
clang builtin function "__builtin_NSStringMakeConstantString" returns const NSConstantString*,
that is not an Objective-C retainable object.
I want to replace this function with my own, but there seems to be no way to declare NSConstantString* as non-Objective-C pointer in Objective-C++ (you can do it in Objective-C by using struct NSConstnatString*). I am sure, that this function returns NSConstantString, because the following two lines output PK16NSConstantString:
printf("%s\n", typeid(__builtin___NSStringMakeConstantString("foo")).name());
printf("%s\n", typeid(const NSConstantString*).name());
Whenever I try to execute the following code I get error "Cannot initialize a variable of type 'const NSConstantString *' with an rvalue of type 'const NSConstantString *'":
const NSConstantString* a = __builtin___NSStringMakeConstantString("foo");
Everything works OK if I add bridge cast, so this means that NSConstantString* is returned as "raw" Objective-C pointer, but I have to create a function that returns exactly the same result as "__builtin_NSStringMakeConstantString", so I have no option to use __bridge.
Whenever I try to return const NSConstantString* from a function, it is always returned as an Objective-C retainable pointer and there seems to be no way to declare it as C pointer except this:
typedef typeof __builtin___NSStringMakeConstantString("") rawNSConstnatStringPtr;
So the question is: Is there a way to declare a nonretainable pointer to NSConstantString* (without using typeof)?
You think _builtin__NSStringMakeConstant returns NSConstantString, because the compiler is tricking you.
I suggest you check out the clang source code: http://llvm.org/docs/GettingStarted.html#git-mirror
Then search the source code: git grep __builtin___NSStringMakeConstantString. You find that it's defined in include/clang/Basic/Builtins.def like this:
BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc")
The second argument is the function signature, and the comment at the top of the file explains what it means. The FC* part is the return type, and means “constant CFString const pointer”. That makes sense since CFString and NSString are toll-free bridged.
But it doesn't make sense because the error message specifically mentions NSConstantString. So git grep -w NSConstantString to see where that's coming from. You eventually find method ASTContext::getCFConstantStringType in lib/ast/ASTContext.cpp. This method creates a struct type declaration with the identifier NSConstantString, but it never adds the declaration to any scope (it doesn't call PushOnScopeChains or AddDecl). So the NSConstantString identifier can appear in diagnostics, but you cannot access the type by name in your source code. The NSConstantString type declared in NSString.h is, as far as the compiler is concerned, unrelated to this synthesized type.
Anyway, the important question is why you want to override __builtin___NSStringMakeConstantString, which you did not say. If it's because you want to use your own constant string class, you're going about it the wrong way.
I don't think you can override that function, because it is built in to the compiler. You would need to modify the compiler source code if you want to change its meaning.
Also, I don't think the compiler actually uses that function to create Objective-C string literals. Running git grep __builtin___NSStringMakeConstantString doesn't turn up any places where the compiler generates a call to it. The compiler handles #"string" syntax in lib/Parse/ParseObjc.cpp and lib/Sema/SemaExprObjC.cpp (look for methods named ParseObjCStringLiteral in both files). The compiler looks up the NSConstantString type by name (which means it should get the one from the NSString.h header file) and creates an instance of ObjCStringLiteral with that type.
You should be able to make it look up a different class for the constant string type (instead of NSConstantString) using the -fconstant-string-class command-line flag, but I don't know how well that works. This question implies that it might not work. Even if it does work, I think you're constrained to using the same memory layout as NSConstantString, in which case, why bother using a different class?
This is from apple blocks docs and I am having difficulty understanding this please can any one explain in little easy way
...You can cast a block reference to a pointer of arbitrary type and
vice versa. You cannot, however, dereference a block reference via the
pointer dereference operator (*)—thus a block's size cannot be
computed at compile time.
Put simply, a block is a reference. The code within the block is stored in memory, and can be accessed via a variable. void (^addingBlock)(int); is a block declaration, that can be accessed via the addingBlock variable (as in, it can be called like addingBlock(5);).
Now, this reference can be transformed into a pointer type, that C recognises. Sort of like a function pointer. As the documentation states, the only visual difference is the use of * instead of ^. This means you can cast a block to a function pointer:
void (*funcPointer)(int) = (void(*)(int))addingBlock;
Or even a void pointer (or any type!)
void* voidPtr = (void*)addingBlock;
But what the quote you're providing says, is that with this pointer to a block, you can't 'dereference' it. This means to interpret the pointer address, and get the data behind that address. Being unable to do this means you can't determine its size at compile time.
Why? Because of Obj-C's dynamic'ness; the contents of the block can only be determined at run time, whereas C is fairly static in nature, and determines a lot at compile time.