In Python, you can give the name of a class as an argument to map in order to create instances of that class:
class Point(object):
def __init__(self, (x, y)):
self.x = x
self.y = y
coords = [(1., 2.), (3., 4.)]
pts = map(Point, coords)
This often proves to be a handy pattern, so I wanted to try the same thing in Swift.
First, we set up our Point class:
import Cocoa
class Point
{
var x: Float
var y: Float
init(x: Float, y: Float) {
self.x = x
self.y = y
}
}
var pt = Point(x: 1, y: 2) // works fine
But when we try to use .map to create instances, we get an error:
let coords: (Float,Float)[] = [(1, 2), (3, 4)]
// (Point).Type is not convertible to '(Float, Float) -> $T3'
var pts = coords.map(Point)
// Initializer cannot be referenced without arguments
var pts = coords.map(Point.init)
What's interesting to me is that if we first define a wrapper function, this does work:
func wrapper(x: Float, y: Float) -> Point {
return Point(x: x, y: y)
}
// This *is* successful
var ptsWrapped = coords.map(wrapper)
Ok, so now I'm curious whether this is a prohibition against using map on methods:
extension Point {
func newPointByAdding(x: Float, y: Float) -> Point {
return Point(x: self.x + x, y: self.y + y)
}
}
// This works as expected
var origin = Point(x: 0, y: 0)
var ptsAdded = coords.map(origin.newPointByAdding)
...nope, that works fine.
I'll freely admit that I haven't yet spent much time with swift, so I may be missing something in the spec which prohibits this.
Is it possible to use map to create new instances of a class/struct in swift?
If not, why not?
is it because init is not a func?
is it something to do with named arguments not being convertible to positional arguments in certain contexts?
Update for Swift 2:
Filing bugs works!
In Swift 2 this is now possible with coords.map(Point.init):
Old answer:
is it because init is not a func?
Yep. In Swift, a function type "consists of a parameter and return type separated by an arrow (->)", and map is defined as func map<U>(transform: (T) -> U) -> [U], i.e. it takes in a function. In the grammar, "function declaration" and "initializer declaration" are treated separately. The latter doesn't have a return type because it's not really a function, just a block of code used to initialize instances. And if you try to pass Point.init, you'll get the error "Initializer cannot be referenced without arguments".
File a bug!
This is now possible in Xcode 7.0 beta 2
from the release notes
Initializers can now be referenced like static methods by referring
to .init on a static type reference or type object:
let x = String.init(5)
let stringType = String.self
let y = stringType.init(5)
let oneTwoThree = [1, 2, 3].map(String.init).reduce(“”, combine: +)
I think your conclusion is correct: init isn't being treated as a conventional func. You might want to report this as a bug; I'm not sure if this is intended behavior or not.
BTW, a more concise way to achieve what you want is:
coords.map{ p => Point(x: p[0], y: p[1]) }
Related
If I have one or more recursive functions inside an Ocaml function how can I call them without exit from the main function taking their value as return of the main function?
I'm new in Ocaml so I'll try to explain me better...
If I have :
let function =
let rec recursive1 = ...
...
let rec recursive2 = ...
...
How can I call them inside function to tell it "Hey, do you see this recursive function? Now call it and takes its value."
Because my problem is that Ocaml as return of my functions sees Unit instead of the right return.
I will post the code below :
let change k v list_ =
let rec support k v list_ =
match list_ with
| [] -> []
| (i,value) :: tl -> if i = k
then (k,v) :: tl
else (i,value) :: support k v tl in
let inserted = support k v list_ in inserted
let () =
let k = [ (1,"ciao");(2,"Hola");(3,"Salut") ] in
change 2 "Aufwidersen" k
Change takes as input a key, a value and a (int * string )list and should return the same list of the input but changing the value linked to the key selected ( if in list ).
support, instead, makes the dirty job. It builds a new list and when k is found i = k it changes value and attach the tile, closing the function.
The return of change is unit when it should be (int * string) list. I think because inserted isn't taken as return of the function.
change does not return unit. The error in fact tells you exactly the opposite, that it returns (int * string) list but that it expects unit. And it expects unit because you're assigning it to a () pattern.
I don't know what you actually intend to do with the return value, as right now you don't seem to care about it, but you can fix the error by just assigning it to a name:
let result: (int * string) list =
let k = [ (1,"ciao");(2,"Hola");(3,"Salut") ] in
change 2 "Aufwidersen" k
Since it's not used I've added a type annotation to make sure we're getting what we expect here, as otherwise result could be anything and the compiler wouldn't complain. You don't typically need this if you're going to use result however, as you'd then get an error if the type doesn't unify with its usage.
I have an interface which looks like this:
interface FontRegionTransformer<R> {
fun transform(region: R, textCharacter: TextCharacter): R
}
I'm not an expert in category theory but as I have learned previously this structure is a monoid (is it?) and I can combine any number of functions which take R and return R together.
This is what I have right now:
var image = source.getSubimage(meta.x * width, meta.y * height, width, height)
regionTransformers.forEach {
image = it.transform(image, textCharacter)
}
This works but I have a question: how do I combine a List of FontRegionTransformers to a single function? Can I do it without adding a compose function to my interface? I tried it with reduce but it did not click.
Clarification: What I'd like to achieve is to combine the functions stored in regionTransformers into a single function so instead of the loop here:
var image = source.getSubimage(meta.x * width, meta.y * height, width, height)
regionTransformers.forEach {
image = it.transform(image, textCharacter)
}
I'd like to have something like this:
var image = source.getSubimage(meta.x * width, meta.y * height, width, height)
return combinedTransformers.invoke(image)
For the composition definition, it is not quite clear, when the composed transformer is called, what textCharacter the second FontRegionTransformer<R> should get. Here, I assume that it is the same textCharacter that is passed into the call, and which is naturally passed to the first transformer.
You can implement the custom composition operation as an extension for FontRegionTransformer<R>:
fun <R> FontRegionTransformer<R>.compose(other: FontRegionTransformer<R>) =
object : FontRegionTransformer<R> {
override fun transform(region: R, textCharacter: TextCharacter): R {
val firstResult = this#compose.transform(region, textCharacter)
return other.transform(firstResult, textCharacter)
}
}
You can add the infix modifier to compose to use the infix notation a compose b, or make it overload an operator + or *, if you like to call it as a * b. Or use a non-extension top-level function for compose(a, b) calls.
Then you can compose two FontRegionTransformers:
val composed = first.compose(second)
And to compose a list of transformers into one, use reduce:
val transformers: List<FontRegionTransformer<SomeType>> = TODO()
val composition = transformers.reduce { a, b -> a.compose(b) }
For FontRegionTransformer<R> to be monoid, the composition operation should be associative (a ∘ (b ∘ c) should be equivalent to (a ∘ b) ∘ c for all a, b and c) and the above implementation seems to satisfy this requirement. But, strictly speaking, it should also have a neutral element, such n that a ∘ n = n ∘ a = a for any a. These two requirements cannot be expressed in terms of the Kotlin type system and should instead be a part of the contract.
A one-statement solution is, inlining compose into the reduce call:
val composition = transformers.reduce { a, b ->
object : FontRegionTransformer<SomeType> {
override fun transform(region: SomeType, textCharacter: TextCharacter) =
a.transform(region, textCharacter).let { b.transform(it, textCharacter) }
}
}
I want to replace an interface's value like this:
package main
import "fmt"
type Fooer interface {Foo(string)}
type Foo struct {foo string}
func (f *Foo) Foo(bar string) {f.foo = bar}
var z = &Foo{foo : "new"}
func swap(fooer Fooer) {fooer = z}
func main() {
f := &Foo{foo: "old"}
fmt.Printf("%s (want &{old})\n", f)
swap(f)
fmt.Printf("%s (want &{new})", f)
}
But i get:
&{old}
&{old}
I tried around with various calls (fooer *= z, *fooer = *z, ..) but I cant seem to get it right.
You can try this example at play.golang: http://play.golang.org/p/EZEh3X8yHC
Okay, I think it works like this:
func swap(fooer Fooer) {
foo, _ := fooer.(*Foo)
*foo = *z
}
Like most things in Go, interfaces are simply values. Assigning a new value within a function isn't going to change the value copied into the function arguments.
Because you want to replace the interface value, you need a pointer to the value just like you would any other. It's a very rare case where you could use a pointer to an interface: http://play.golang.org/p/EZEh3X8yHC
func swap(fooer *Fooer) {
z := Fooer(&Foo{foo: "new"})
*fooer = z
}
func main() {
var f Fooer = &Foo{foo: "old"}
fmt.Printf("%s (want &{old})\n", f)
swap(&f)
fmt.Printf("%s (want &{new})", f)
}
But, since a pointer to an interface is almost always a mistake (you can see we have to be very explicit to make this work), you should really have a good reason for implementing something this way, and document it well.
What you most likely want is to extract the pointer from the interface, and assign a new value in there (which is what you added to end of your question). This is a much better construct, but the type must match, so the interface isn't needed.
I am trying to do this:
var dictArray = [String:[String]]()
dictArray["test"] = [String]()
dictArray["test"]! += "hello"
But I am getting the weird error NSString is not a subtype of 'DictionaryIndex<String, [(String)]>'.
I just want to be able to add objects to an array inside a dictionary.
Update: Looks like Apple considers this a "known issue" in Swift, implying it will work as expected eventually. From the Xcode 6 Beta 4 release notes:
...Similarly, you cannot modify the underlying value of a mutable
optional value, either conditionally or within a force-unwrap:
tableView.sortDescriptors! += NSSortDescriptor(key: "creditName", ascending: true)
Workaround: Test the optional value explicitly and then assign the
result back:
if let window = NSApplication.sharedApplication.mainWindow {
window.title = "Currently experiencing problems"
}
tableView.sortDescriptors = tableView.sortDescriptors!
You can only do this
var dictArray = [String:[String]]()
dictArray["test"] = [String]()
var arr = dictArray["test"]!;
arr += "hello"
dictArray["test"] = arr
because dictArray["test"] give you Optional<[String]> which is immutable
6> var test : [String]? = [String]()
test: [String]? = 0 values
7> test += "hello"
<REPL>:7:1: error: '[String]?' is not identical to 'UInt8'
append also won't work due to the same reason, Optional is immutable
3> dictArray["test"]!.append("hello")
<REPL>:3:18: error: '(String, [(String)])' does not have a member named 'append'
dictArray["test"]!.append("hello")
^ ~~~~~~
BTW the error message is horrible...
You may use NSMutableArray instead of [String] as a value type for your dictionary:
var dictArray: [String: NSMutableArray] = [:]
dictArray["test"] = NSMutableArray()
dictArray["test"]!.addObject("hello")
This is still an issue in Swift 3. At least I was able to create method that can handle it for you.
func appendOrCreate(newValue: Any, toArrayAt key: String, in existingDictionary: inout [AnyHashable:Any]) {
var mutableArray = [Any]()
if let array = existingDictionary[key] as? [Any]{
//include existing values in mutableArray before adding new value
for existingValue in array {
mutableArray.append(existingValue)
}
}
//append new value
mutableArray.append(newValue)
//save updated array in original dictionary
existingDictionary[key] = mutableArray
}
The problem is that we want class semantics here but have to use structs. If you put class objects into the dictionary, you get what you want!
So, if you have¹ to have mutable values, you can wrap them in a class and perform updates with a closure:
class MutableWrapper<T> {
var rawValue: T
init(_ val: T) {
self.rawValue = val
}
func update(_ with: (inout T) -> Void) {
with(&self.rawValue)
}
}
Example:
func foo() {
var dict = [String: MutableWrapper<[String]>]()
dict["bar"] = MutableWrapper(["rum"])
dict["bar"]?.update({$0.append("gin")})
print(dict["bar"]!.rawValue)
// > ["rum", "gin"]
}
For what it's worth, I do not see a way to keep caller and wrapper in sync. Even if we declare init(_ val: inout T) we will end up with a copy in rawValue.
Performance is not necessarily an issue since the compiler optimizes structs heavily. I'd benchmark any mutable solution against what looks like lots of copy-updates in the code.
Since Swift 4.1 you can provide a default value to the subscript which allows you to solve this quite naturally now:
dictArray["test", default: []].append("hello")
How to create a Map that I will have a key: (int * int) and when it comes to key it is my_own_type ?
Here's a small example:
module IPMap = Map.Make(struct type t = int * int let compare = compare end)
let mymap = IPMap.add (0, 0) (my_value : my_own_type) IPMap.empty
let mymap' = IPMap.add (1, 2) (t: my_own_type) mymap
Note: you don't have to write (t: my_own_type). You can just write t. I'm including it just for emphasis.
When you create a map module like IPMap, you only need to specify the type of the keys. You can have as many different maps with different value types as you like.
Note 2: OCaml maps are immutable. I worry that you haven't fully grappled with this issue yet. (Apologies if I'm wrong.)