[Discussion] Updating Struct Values While Looping


(Paul Ossenbruggen) #1

So I have some code that utilizes structs, I would like to go through and update some of the values. While I could use map, it seems I should be able to do it using a for in loop without utilizing indexes. The mutate2 method uses enumerate, and the index to write back the copy to the array, but I would prefer to update the struct value itself and avoid having to use indexes as I try to avoid them, if possible.. It seems the structs kind of force you to go back to indexes. I was thinking that it would be useful to be able to apply the & (reference) operator here to allow direct access to the array element struct, an example of this is shown in mutate3. With a class this is not necessary. I know a little like C++ but just want to explore this idea unless there is some other way I missed.

struct Codon {
    var val = Float(0.0)
    var mask = false
}

class Geno {
    var codons : [Codon]

    // pure index based approach
    func mutate() {
        for i in 0..<codons.count {
            if !codons[i].mask {
                codons[i].val += r.gauss() * vari
            }
        }
    }

    // index to write back, less efficient?
    func mutate2() {
        for (index, var codon) in codons.enumerate() {
            if !codon.mask {
                codon.val += r.gauss()
                codons[index] = codon
            }
        }
    }

    // suggested reference approach
    func mutate3() {
        for var &codon in codons {
            if !codon.mask {
                codon.val += r.gauss()
            }
        }
    }
}


(Dmitri Gribenko) #2

This would be a useful extension to the language (but it is not clear
how to define it -- do we need to hardcode the knowledge about the
MutableCollection protocol into the compiler?)

There's something you can do today, though:

extension MutableCollectionType {
  public mutating func mutatingEach(mutate: (inout Generator.Element) -> Void) {
    for i in self.indices {
      mutate(&self[i])
    }
  }
}

var a = [1,2,3]
a.mutatingEach { (x: inout Int) -> Void in x += 1 }
//a.mutatingEach { $0 += 1 } // does not work, probably due to a compiler bug.
print(a)

Dmitri

···

On Mon, Mar 7, 2016 at 12:57 AM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org> wrote:

    func mutate3() {
        for var &codon in codons {
            if !codon.mask {
                codon.val += r.gauss()
            }
        }
    }
}

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Pyry Jahkola) #3

I don't disagree, but quick reminder: you might want to use `indices` instead of `..<`:

for i in codons.indices { codons[i] = ... }

— Pyry

···

On 07 Mar 2016, at 10:57, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org> wrote:

for i in 0..<codons.count { codons[i] = ... }


(Dmitri Gribenko) #4

    func mutate3() {
        for var &codon in codons {
            if !codon.mask {
                codon.val += r.gauss()
            }
        }
    }
}

This would be a useful extension to the language (but it is not clear
how to define it -- do we need to hardcode the knowledge about the
MutableCollection protocol into the compiler?)

There's something you can do today, though:

extension MutableCollectionType {
  public mutating func mutatingEach(mutate: (inout Generator.Element) -> Void) {

This method should be called 'mutateEach' to conform to the guidelines, though.

Dmitri

···

On Mon, Mar 7, 2016 at 2:24 AM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Mon, Mar 7, 2016 at 12:57 AM, Paul Ossenbruggen via swift-evolution > <swift-evolution@swift.org> wrote:

    for i in self.indices {
      mutate(&self[i])
    }
  }
}

var a = [1,2,3]
a.mutatingEach { (x: inout Int) -> Void in x += 1 }
//a.mutatingEach { $0 += 1 } // does not work, probably due to a compiler bug.
print(a)

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Joe Groff) #5

This should be fixed in 7.3, for what it's worth.

-Joe

···

On Mar 7, 2016, at 2:24 AM, Dmitri Gribenko via swift-evolution <swift-evolution@swift.org> wrote:

var a = [1,2,3]
a.mutatingEach { (x: inout Int) -> Void in x += 1 }
//a.mutatingEach { $0 += 1 } // does not work, probably due to a compiler bug.
print(a)


(Paul Ossenbruggen) #6

Thanks for pointing this out!

···

Sent from my iPhone

On Mar 7, 2016, at 10:11 AM, Pyry Jahkola <pyry.jahkola@iki.fi> wrote:

On 07 Mar 2016, at 10:57, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org> wrote:

for i in 0..<codons.count { codons[i] = ... }

I don't disagree, but quick reminder: you might want to use `indices` instead of `..<`:

for i in codons.indices { codons[i] = ... }

— Pyry


(Dmitri Gribenko) #7

I was testing on master.

Dmitri

···

On Mon, Mar 7, 2016 at 8:59 AM, Joe Groff <jgroff@apple.com> wrote:

On Mar 7, 2016, at 2:24 AM, Dmitri Gribenko via swift-evolution > <swift-evolution@swift.org> wrote:

var a = [1,2,3]
a.mutatingEach { (x: inout Int) -> Void in x += 1 }
//a.mutatingEach { $0 += 1 } // does not work, probably due to a compiler
bug.
print(a)

This should be fixed in 7.3, for what it's worth.

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Joe Groff) #8

Sounds like we have a regression in master, then. It worked for me in a 7.3 beta playground.

-Joe

···

On Mar 7, 2016, at 9:00 AM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Mon, Mar 7, 2016 at 8:59 AM, Joe Groff <jgroff@apple.com> wrote:

On Mar 7, 2016, at 2:24 AM, Dmitri Gribenko via swift-evolution >> <swift-evolution@swift.org> wrote:

var a = [1,2,3]
a.mutatingEach { (x: inout Int) -> Void in x += 1 }
//a.mutatingEach { $0 += 1 } // does not work, probably due to a compiler
bug.
print(a)

This should be fixed in 7.3, for what it's worth.

I was testing on master.


(Dmitri Gribenko) #9

https://bugs.swift.org/browse/SR-892

Dmitri

···

On Mon, Mar 7, 2016 at 9:02 AM, Joe Groff <jgroff@apple.com> wrote:

On Mar 7, 2016, at 9:00 AM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Mon, Mar 7, 2016 at 8:59 AM, Joe Groff <jgroff@apple.com> wrote:

On Mar 7, 2016, at 2:24 AM, Dmitri Gribenko via swift-evolution >>> <swift-evolution@swift.org> wrote:

var a = [1,2,3]
a.mutatingEach { (x: inout Int) -> Void in x += 1 }
//a.mutatingEach { $0 += 1 } // does not work, probably due to a compiler
bug.
print(a)

This should be fixed in 7.3, for what it's worth.

I was testing on master.

Sounds like we have a regression in master, then. It worked for me in a 7.3 beta playground.

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/