Swift: Recursive Value Type

3.2k views Asked by At

I have a structure in which I want to have a global variable of type Struct?. This example is essentially a briefer version of the structure I am actually creating.

struct SplitString { //splits a string into parts before and after the first "/"

    var preSlash: String = String()
    var postSlash: SplitString? = nil

    init(_ str: String) {
        var arr = Array(str)
        var x = 0
        for ; x < arr.count && arr[x] != "/"; x++ { preSlash.append(arr[x]) }
        if x + 1 < arr.count { //if there is a slash
            var postSlashStr = String()
            for x++; x < arr.count; x++ {
                postSlashStr.append(arr[x])
            }
            postSlash = SplitString(postSlashStr)
        }
    }

}

However, it throws the error:

Recursive value type 'SplitString' is not allowed

Is there any way to get around this? Any help would be great. Thanks :)

Edit: In case it is relevant, I am programming on iOS, not OSX.

Edit: If I have:

var split = SplitString("first/second/third")

I would expect split to be:

{preSlash = "first", postSlash = {preSlash = "second", postSlash = {preSlash = "third",
postSlash = nil}}}
2

There are 2 answers

2
Chris Conover On BEST ANSWER

TL;DR:

What you are trying to achieve is easily accomplished using split:

for s in split("first/second/third", { c in c == "/" } ) {
    println("\(s)")
}

Discussion:

It seems like you are trying to write a linked list of value types. The problem is that Swift couples the concepts of copy semantics with value / reference access. (unlike say C++ which allows you to create the same object on the stack or heap). The solution would seem to be wrapping it in a reference container aka class.

class SplitString { //splits a string into parts before and after the first "/"

    var preSlash: String = String()
    var postSlash: Wrapped? = nil

    init(_ str: String) {
        var arr = Array(str)
        var x = 0
        for ; x < arr.count && arr[x] != "/"; x++ { preSlash.append(arr[x]) }
        if x + 1 < arr.count { //if there is a slash
            var postSlashStr = String()
            for x++; x < arr.count; x++ {
                postSlashStr.append(arr[x])
            }
            postSlash = Wrapped(postSlashStr)
        }
    }

}

class Wrapped {
    var split:SplitString

    init(var _ str:String) {
        split = SplitString(str)
    }
}

Note that this code compiles as a proof of concept but I haven't delved into your algorithm or tested it.

Edit:

In response to your edits above, this code will exercise your code above and yield the splits you want:

for (var s:SplitString? = split; s != nil; s = s?.postSlash?.split) {
    println("\(s!.preSlash)")
}

Obviously having turtles all the way down doesn't make sense, per the discussion above, so you need to break the cycle, as was the case with the class containing your struct.

Note that I have been trying to answer the question that you posted, not the problem that you have. The solution to the problem that you have, is to use SequenceOf and GeneratorOf to create a sequence wrapped generator that iterates through the slashes and returns the substrings between. This is actually done for you via the split function:

for s in split("first/second/third", { c in c == "/" } ) {
    println("\(s)")
}
0
Enrico Granata On

I imagine this is because an Optional behaves like a value type. So what you have is a value type of a value type. A value type.

In order to do layout for a value type, you need to know the size of things involved.

So you have (simplified):

sizeof(SplitString) = sizeof(String) + sizeof(SplitString?)

with

sizeof(SplitString?) > sizeof(SplitString)

since you need to store the fact that the value is or is not present (and, no, a pattern of sizeof(SplitString) zeros is not a valid representation for that as it would be for a class type - why? imagine Int? = 0)

So, now you have

sizeof(SplitString?) > sizeof(String) + sizeof(SplitString?)

but all quantities involved are definitely > 0. Rather the absurd, right?