Still trying out swift, and I came across this problem (not sure if it really classifies as one)
So we have a protocol, and a structure that inherits it.
protocol ExampleProtocol {
var simpleDescription: String { get }
func adjust()
}
struct SimpleStructure : ExampleProtocol{
var simpleDescription = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
func adjust() { //I created this second method just to conform to the protocol
}
}
var b = SimpleStructure()
b.adjust() //This generates a compiler error mentioning Ambiguity (Correct)
Question is how do I call the mutating adjust() not the adjust from the protocol. i.e. I know if I declare b as a protocol and initialized it to the struct it will call adjust from protocol, but how do I call the first adjust ? or is it not possible? Or Am I using it wrongly ?
Cheers,
Your code doesn't compile, but the error is in redefining the adjust method by adding the mutating attribute - that doesn't create an overloaded version of adjust.
In my opinion this is the correct code:
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
struct SimpleStructure : ExampleProtocol{
var simpleDescription = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
which means: you have to define the adjust function as mutating in the protocol.
Related
For example, consider the following C# code:
interface IBase { void f(int); }
interface IDerived : IBase { /* inherits f from IBase */ }
...
void SomeFunction()
{
IDerived o = ...;
o.f(5);
}
I know how to get a MethodDefinition object corresponding to SomeFunction.
I can then loop through MethodDefinition.Instructions:
var methodDef = GetMethodDefinitionOfSomeFunction();
foreach (var instruction in methodDef.Body.Instructions)
{
switch (instruction.Operand)
{
case MethodReference mr:
...
break;
}
yield return memberRef;
}
And this way I can find out that the method SomeFunction calls the function IBase.f
Now I would like to know the declared type of the object on which the function f is called, i.e. the declared type of o.
Inspecting mr.DeclaringType does not help, because it returns IBase.
This is what I have so far:
TypeReference typeRef = null;
if (instruction.OpCode == OpCodes.Callvirt)
{
// Identify the type of the object on which the call is being made.
var objInstruction = instruction;
if (instruction.Previous.OpCode == OpCodes.Tail)
{
objInstruction = instruction.Previous;
}
for (int i = mr.Parameters.Count; i >= 0; --i)
{
objInstruction = objInstruction.Previous;
}
if (objInstruction.OpCode == OpCodes.Ldloc_0 ||
objInstruction.OpCode == OpCodes.Ldloc_1 ||
objInstruction.OpCode == OpCodes.Ldloc_2 ||
objInstruction.OpCode == OpCodes.Ldloc_3)
{
var localIndex = objInstruction.OpCode.Op2 - OpCodes.Ldloc_0.Op2;
typeRef = locals[localIndex].VariableType;
}
else
{
switch (objInstruction.Operand)
{
case FieldDefinition fd:
typeRef = fd.DeclaringType;
break;
case VariableDefinition vd:
typeRef = vd.VariableType;
break;
}
}
}
where locals is methodDef.Body.Variables
But this is, of course, not enough, because the arguments to a function can be calls to other functions, like in f(g("hello")). It looks like the case above where I inspect previous instructions must repeat the actions of the virtual machine when it actually executes the code. I do not execute it, of course, but I need to recognize function calls and replace them and their arguments with their respective returns (even if placeholders). It looks like a major pain.
Is there a simpler way? Maybe there is something built-in already?
I am not aware of an easy way to achieve this.
The "easiest" way I can think of is to walk the stack and find where the reference used as the target of the call is pushed.
Basically, starting from the call instruction go back one instruction at a time taking into account how each one affects the stack; this way you can find the exact instruction that pushes the reference used as the target of the call (a long time ago I wrote something like that; you can use the code at https://github.com/lytico/db4o/blob/master/db4o.net/Db4oTool/Db4oTool/Core/StackAnalyzer.cs as inspiration).
You'll need also to consider scenarios in which the pushed reference is produced through a method/property; for example, SomeFunction().f(5). In this case you may need to evaluate that method to find out the actual type returned.
Keep in mind that you'll need to handle a lot of different cases; for example, imagine the code bellow:
class Utils
{
public static T Instantiate<T>() where T : new() => new T();
}
class SomeType
{
public void F(int i) {}
}
class Usage
{
static void Main()
{
var o = Utils.Instantiate<SomeType>();
o.F(1);
}
}
while walking the stack you'll find that o is the target of the method call; then you'll evaluate Instantiate<T>() method and will find that it returns new T() and knowing that T is SomeType in this case, that is the type you're looking for.
So the answer of Vagaus helped me come up with a working implementation.
I published it on github - https://github.com/MarkKharitonov/MonoCecilExtensions
Included many unit tests, but I am sure I missed some cases.
I am completely baffled. I am essentially trying to do foo["x"]="y" and getting the most baffling of exceptions. I actually made a minimal working example, and I had to nest Maps and Lists for the thing to break. I have no idea what's going on.
Map fixprobset(Map P) {
print(P);
if(!P.containsKey("name")) {
final foo = P["tileset"].join(" ");
P["name"] = foo;
}
if(P.containsKey("children")) {
for(var k=0; k<P["children"].length;k++) fixprobset(P["children"][k]);
}
return P;
}
void main() {
Map problemset = fixprobset({
"name": "Jingle Jangle",
"children": [
{
"tileset": ["1","2","3"]
}
]
});
print(problemset);
}
Click here and gaze in wonder on the bafflement
OK so now I understand what's going on. Objects have a runtimeType, and even though P has the unassuming type declaration Map, P.runtimeType could be e.g. Map<String,List<String>>. Once that happens, a Map can no longer store heterogeneous objects. Getting around this was quite hard for me, the type declarations Map<String,dynamic> P or Map<String,Object> P really don't help, the undesirable runtimeType is there to stay. I've filed this as a "bug" although perhaps it will be deemed a (mis)feature.
This gist has the workaround.
You problems comes from the fact that your are fighting against the type system in Dart. As you have discovered, there are something about the runtimeType which seems to be automatically assigned to some other type than dynamic.
I have made this example which works:
Map fixprobset(Map<dynamic, dynamic> P) {
print(P);
if (!P.containsKey("name")) {
final foo = (P["tileset"] as List).join(" ");
P["name"] = foo;
}
if (P.containsKey("children")) {
for (var k = 0; k < (P["children"] as List).length; k++) {
fixprobset((P["children"] as List)[k] as Map);
}
}
return P;
}
void main() {
final problemset = fixprobset(<dynamic, dynamic>{
"name": "Jingle Jangle",
"children": <dynamic>[
<dynamic, dynamic>{
"tileset": <dynamic>["1", "2", "3"]
}
]
});
print(problemset);
}
As you can see, the automatically assigned types comes from your input data which gets assigned types which makes sense at the start of the program. Your problem is then, that you don't wants this automatically assigned types but want to change them after creation. So you want to change a List<String> into a List<dynamic> but to do that, you need to create a new object since you cannot change the type of an object after its creation.
So my "solution" fixes this by setting the type at the time of the creation of the lists and maps in the input of the first call to fixprobset.
TL;DR: How does one modify content inside a ForEach structure?
The following is a self-contained Playground, in which the call to frame() is OK in a plain body method, but is a syntax error when wrapped in a ZStack/ForEach loop.
import UIKit
import SwiftUI
struct Item: Identifiable {
var id = UUID()
var name: String
init(_ name:String) { self.name = name }
}
let items = [
Item("a"), Item("b"), Item("c")
]
struct ContentView: View {
var body: some View {
return Image("imageName")
.resizable()
.frame(width:0, height:0) // This compiles.
}
var body2: some View {
ZStack {
ForEach(items) { item -> Image in // Return type required...
let i = item // ...because of this line.
return Image(i.name)
.resizable() // Parens required.
.frame(width: 0, height: 0) // Compile error.
}
}
}
}
Note the line let i = item. It is standing in for code in my app that performs some calculations. The fact that the ForEach closure is not a single expression caused the compiler to complain
Unable to infer complex closure return type; add explicit type to disambiguate.
which motivated my adding the return type. But that brings about the topic of this question, the compiler error:
Cannot convert return expression of type 'some View' to return type 'Image'
It appears that the return value of the frame() call is not an Image but a ModifiedContent<SwiftUI.Image, SwiftUI._FrameLayout>.
I have discovered (thanks to commenters!) I can get around this by (somehow) reducing the ForEach closure to a single expression, which renders inferrable the return type, which I can then remove. Is this my only recourse?
As far as I can tell, this may just be a limitation of Swift, analogous to or part of this type-inference issue: Why can't the Swift compiler infer this closure's type?
My workaround has been to add functionality to the Item struct. Now every calculation needed inside the ForEach closure is provided by the item instance, in-line to the Image initializer, like this:
var body3: some View {
ZStack {
ForEach(items) { item in // No return type specified.
// let (width, height) = ... // Remove pre-calculations that
// confused the compiler.
Image(item.name)
.resizable()
.frame(
width : item.width, // All needed data are
height: item.height // provided in closure param.
)
}
}
}
}
I will grant that this is more idiomatically functional, though I prefer the clarity of a few well-chosen assignments preceding the call. (If the calculations for the assignments are side-effect-free, then it is essentially SSA-style, which should pass the FP smell test.)
So I call this an “answer”, even a “solution”, although I can still whinge about the unhelpful error messages. But that is a known issue, and smarter people than me are already on that.
This is here
ForEach(items) { item -> Image in
you explicitly specify that closure returns Image, but frame returns some View, so type mismatch and compiler error.
Use just as below and it will work
ForEach(items) { item in
Now the mesh, I'll have to think about. But getting that first error to go away requires conforming Item with identifiable.
struct Item: Identifiable {
var id = UUID()
var name: String
var size: CGSize = .zero
}
I also had to write a custom modifier for using the item to create a frame. We'll likely want to use CGRect for the mesh creation, have some way to mess with the origin of the image.
extension View {
func frame(with size: CGSize) -> some View {
frame(width: size.width, height: size.height)
}
}
Then your body will look something like this.
var body: some View {
ZStack {
ForEach(items) { item in
Image(item.name).resizable().frame(with: item.size)
}
}
}
How does one set an optional property of a protocol? For example UITextInputTraits has a number of optional read/write properties. When I try the following I get a compile error (Cannot assign to 'keyboardType' in 'textInputTraits'):
func initializeTextInputTraits(textInputTraits: UITextInputTraits) {
textInputTraits.keyboardType = .Default
}
Normally when accessing an optional property of a protocol you add a question mark but this doesn't work when assigning a value (error: Cannot assign to the result of this expression):
textInputTraits.keyboardType? = .Default
The protocol looks like:
protocol UITextInputTraits : NSObjectProtocol {
optional var keyboardType: UIKeyboardType { get set }
}
It's impossible in Swift (yet?). Referenced from an ADF thread:
Optional property requirements, and optional method requirements that return a value, will always return an optional value of the appropriate type when they are accessed or called, to reflect the fact that the optional requirement may not have been implemented.
So it's no surprise to get optional values easily. However, setting a property requires implementation to be guaranteed.
I'd consider making an extension returning your default value for keyboardType, and having the setter do nothing.
extension UITextInputTraits {
var keyboardType: UIKeyboardType {
get { return .default }
set { /* do nothing */ }
}
}
That way you can remove the optional from your property declaration.
protocol UITextInputTraits : NSObjectProtocol {
var keyboardType: UIKeyboardType { get set }
}
Or, if you prefer, you can make it of optional return type, var keyboardType: UIKeyboardType?, and return nil instead of .Default in your extension.
This way, you can test for myObject.keyboardType == nil to see if your property is implemented.
One workaround is to create another protocol that conforms to the first one, but that declare that optional property as mandatory. Then to try to cast the object as that new protocol, and if the cast succeed, we can access the property directly.
protocol UITextInputTraitsWithKeyboardType : UITextInputTraits {
// redeclare the keyboardType property of the parent protocol, but this time as mandatory
var keyboardType: UIKeyboardType { get set }
}
func initializeTextInputTraits(textInputTraits: UITextInputTraits) {
// We try to cast ('as?') to the UITextInputTraitsWithKeyboardType protocol
if let traitsWithKBType = textInputTraits as? UITextInputTraitsWithKeyboardType {
// if the cast succeeded, that means that the keyboardType property is implemented
// so we can access it on the casted variable
traitsWithKBType.keyboardType = .Default
}
// (and if the cast failed, this means that the property is not implemented)
}
I also demonstrated that at the bottom on this SO answer if you want another example of the idea.
The following is what I came up with for Swift 2.2 compatibility:
#objc protocol ComponentViewProtocol: class {
optional var componentModel: ComponentModelProtocol? { get set }
optional var componentModels: [String:ComponentModelProtocol]? { get set }
}
class ComponentView: NSObject, ComponentViewProtocol {
var componentModel: ComponentModelProtocol?
...
..
.
}
class SomeCodeThatUsesThisStuff {
func aMethod() {
if var componentModel = componentView.componentModel {
componentModel = .... (this succeeds - you can make assignment)
} else if var componentModels = componentView.componentModels {
componentModels = .... (this failed - no assignment possible)
}
}
}
In essence you need to perform an "if/let binding" on the optional property to ensure it actually is implemented? If it's nil then the encapsulating object didn't implement it, but otherwise you can now make assignments to it and the compiler will no longer complain.
I have a function like this:
private downloadAllFiles() {
sftpRetriever.listFiles().findAll {
filter.isResponse(it) || filter.isResponseTurned(it)
}.each { String fileName ->
log.info 'Downloading file: {}', fileName
sftpRetriever.downloadFile(fileName)
log.info 'File downloaded'
removeRemoteFile(fileName)
}
}
I am looking for a simple way of modyfing this closure inside of that function so if the size() of findAll is 0 it will simply log 'No more files to download' and .each won't be executed. Is there any simple way to make it in single closure? It is really simply task if I divide it in several parts, but trying to learn closures here and improve my expressiveness :) Thank you in advance for your help.
Take a look at creature below :) It works due the fact that each returns the collection on which it's invoked (+ elvis operator and quite nice Groovy's truth evaluation):
def printContents(Collection collection) {
collection.each {
println it
} ?: println('Collection is empty')
}
printContents([1,2,'hello'])
printContents([])
I don't like this syntax but it's the shorter version which came to my mind.
You can also use metaprogramming to add the method provided by Steinar. It must be added to metaClass before first use but you'll avoid an effort to make extension module:
Collection.metaClass.doIfEmpty { Closure ifEmptyClosure ->
if (delegate.empty) {
ifEmptyClosure()
}
return delegate
}
def printContents(Collection collection) {
collection.doIfEmpty {
println "Collection is empty"
}.each {
println it
}
}
printContents([1,2,'hello'])
printContents([])
One rather generic and reusable option is to extend Collection using an extension module. This is surprisingly easy to do and is even recognized in IDE's (at least in IntelliJ) so you get code completion, etc.
For example, write an the extension class for collections which will perform the closure if the collection is empty. In addtion, it should always return the collection to allow further chaining:
package stackoverflow
class CollectionExtension {
static <T extends Collection> T doIfEmpty(T self, Closure closure) {
if (self.empty) {
closure()
}
return self
}
}
You will also need to tell groovy that this file is an extension module. Add a property file as a resource on the classpath: META-INF/services/org.codehaus.groovy.runtime.ExtensionModule (note: this name and location is mandatory for extension modules, i.e. you cannot change it).
moduleName=stackoverflow-module
moduleVersion=1.0
extensionClasses=stackoverflow.CollectionExtension
Finally a simple test script to show how this can be used:
def printContents(Collection collection) {
collection.doIfEmpty {
println "Collection is empty"
}.each {
println it
}
}
printContents([1,2,'hello'])
printContents([])
Output:
1
2
hello
Collection is empty
You may try the following piece of code:
def l1 = [1,2,3,4]
def l2 = [5,6,7,8]
def m(list) {
list.findAll { it < 5}.with { l ->
size > 0 ?
l.each { e ->
println e
}
:
println('Zero elements found')
}
}
m(l1)
m(l2)
No better idea at the moment.