12
\$\begingroup\$

My code is attempting to implement FP in an efficient / readable manner into some of my video games. I realize this may be a bit subjective, but I feel there is enough merit / objectivity to be of benefit to the community.

Why I'm asking for a review:

I'm not sure that my code is executing FP / procedural principles in an efficient manner, meaning if my attempts at FP / procedural are not good enough to be worth switch from mutable-state programming...

Or, if there are simpler ways of implementing what I'm trying to do functionally (I'm looking for a reasonable amount efficiency / low-verbosity), that would be cool.

Goal:

To make a single, mutable var 'cat list'; this list contains immutable Cat instances that can battle one another.

It's done in Swift 2.2. Here is a link to an online playground for 2.2 with my program loaded. Otherwise, you can run it in any main.swift console or Xcode playground if desired:

Documentation:

//: Playground - noun: a place where cats can play (with rockets).

/* BATTLE CATS!! Fed up with being "cutified," one faction of furry-
                 friends has decided to destroy all servers and the 
                 Internet!! 

                 Tech-loving felines across the globe have
                 taken up arms to protect their fame, fortune, and 
                 web-based addiction. Choose your side, load up, and
                 BATTLE WITH CATS!!!

 Goal:
   - 1. To make an immutable OOP-style Cat object with FP principles.
   - 2. To make a single, mutable var 'cat list' that contains all Cat objects
   - 3. To easily (non verbosely) have Cats battle each other, in a functional way.


Conventions:

  camelCase:
    - Global Mutable:   gGlobalName
    - External Pram:    pramName
    - Labels:           labelName
    - Named Closures:   closureName()
    - Enum Case:        caseName

  PascalCase:
    - Struct/Type:      ClassName

  under_score:
    - Locals:           local_name
    - Parameter:        pram_name

  UPPERCASE:
    - Constant Fields
      (Non-transform):  FIELDNAME
    - Global Constant:  gCONSTANT


Methods / Funcs:
  - Are non-mutating, pass in a value, and always return a value.
    However, named closures do not necessarily return a value 
    or pass in data (they are convenience).

  - Pass 'self' "implicitly" (to reduce verbosity, etc.)
    I still consider this "pure", though not referentailly transparent,
    Since explicitly passing a `Cat` could produce the wrong expected outcome.

  - Sub-functions may not always pass outer-pram for
    verbose reasons ( see matchName() )

  - Data used in the 'return' call or logic expressions
    are usually declared and commented as "Returners" wih no value;
    the subsequent `logicLabel do:' will assign the value.


Structs:
  - 'Cat' instances transform via constructor with
    default-parameters; a passed in "copyCat" pram
    is used to copy from. 

    This is a psuedo-oop struct, but with FP principles.

    The main initializer is a series of default prams set to nil,
    and an 'copyCat' pram that is used to copy from. By
    setting a pram to Not Nil, you effectively transform only one field.

    CatList and Battle structs are not required to make Cats battle.

  - 'CatList' is to be used as a singleton, but is handled
    in a similar way to Cat--but currently CatList
    has no methods (it is a data structure of Cat instances).

  - 'Battle' is not necessary, but was created to make handling CatList and Cat
    more easily and less verbosely. It is a "static func-struct" (no fields);
    essentially a "utility class" from Java, etc.

TODO:
  - Make more enums (alive, dead, etc)
  - Implement random battles (unnamed cats)
  - Test performance
  - Make unit tests (not assertions)
  - Simplify handleResults()

NOTE:
  - Many, MANY, virtual cats were harmed in the making
    of this program ;)
*/

Main struct:

/** Says meow... Then fires a rocket at your face: */
struct Cat {

// TODO: Add enooms for Faction, Status, etc.

/* Fields: */

  // Transformable:
  let age:         Int,
      name:        String,
      rockets:     Int, // Our kitty is srsbznz... bin' warn3d..
      lives:       Int,
      status:      String,
      hp:          Int,
      dmg_to_give: Int

  // Constants:
  let AP    = 40,
      DEF   = 20,
      MAXHP = 50

  // Name Closures:
  let meow = { print($0) }


/* Inits: */

  /// Default init for new cat. Use 'init(fromOldCat:)' to transform.
  init(newCatWithName _name: String) {
    age = 5; name = _name; rockets = 5; lives = 9;
    dmg_to_give = 0; hp = self.MAXHP; status = "Alive"

    meow("  Nyaa! Watashi wa \(self.name) desu~!") // Purrrr...
  }

  /// Call for FP transformation:
  init(copyCat cc:          Cat,
               age:         Int?    = nil,
               name:        String? = nil,
               rockets:     Int?    = nil,
               lives:       Int?    = nil,
               status:      String? = nil,
               hp:          Int?    = nil,
               dmg_to_give: Int?    = nil) {

    // Basics:
    age     == nil  ?  (self.age     = cc.age)     : (self.age     = age!    )
    name    == nil  ?  (self.name    = cc.name)    : (self.name    = name!   )
    rockets == nil  ?  (self.rockets = cc.rockets) : (self.rockets = rockets!)
    lives   == nil  ?  (self.lives   = cc.lives)   : (self.lives   = lives!  )
    status  == nil  ?  (self.status  = cc.status)  : (self.status  = status! )
    hp      == nil  ?  (self.hp      = cc.hp)      : (self.hp      = hp!     )

    // Battle:
    dmg_to_give == nil ? (self.dmg_to_give = cc.dmg_to_give):(self.dmg_to_give = dmg_to_give!)

    // New cat purrs...
    if (self.name != cc.name) { meow("  Nyaa! Watashi wa \(self.name) desu~!") }
  }


/* Methods: */  // NOTE: All methods pass 'self' into parameter "implicitly" (pseudo-pure).

/** Calculates damage to give (from $0's DEF), then stores it in own field:

  cat1 = cat1.fireRocket(at: cat2)
*/
  func fireRocket(at victim: Cat) -> Cat {

    // Returners:
    let dmg_to_give2 = (self.AP - victim.DEF)
    let rockets2     = (self.rockets - 1)

    // TODO: Add a self.rockets check before firing a rocket
    return Cat(copyCat: self, rockets: rockets2, dmg_to_give: dmg_to_give2)
  }


/** Decreases own HP from value stored in other cat, then updates

  cat2 = cat2.takeDamage(from: cat1)
*/
  func takeDamage(from attacker: Cat) -> Cat {

    // Returners:
    let hp2:     Int,
        lives2:  Int,
        status2: String

    assignmentLogic: do {

      // Logic fodder:
      let dmg_taken = attacker.dmg_to_give
      let dam_left  = (self.hp - dmg_taken)

      // Our cat dies:
      if dam_left <= 0 {
        hp2    = self.MAXHP
        lives2 = (self.lives - 1)

        lives2 == 0 ? (status2 = "Dead") : (status2 = "Alive")
      }

      // Our cat lives:
      else {
        hp2     = dam_left
        lives2  = self.lives
        status2 = "Alive"
      }
    }

    return Cat(copyCat: self, hp: hp2, lives: lives2, status: status2 )
  }


/** Should be called after attacking cat uses a '.attack()', to reset dmgToGive.

  cat1 = cat1.readyForNextBattle()
*/
  func readyForNextBattle(/* Uses 'self'*/) -> Cat {
    return Cat(copyCat: self, dmg_to_give: 0)
  }

  // End of Cat />
}

First test:

/* First Test */

// Makes transformation more obvious than '=' operator.. lhs 'does' rhs (transforms into):
infix operator ->>{}; func ->> <T> (inout l: T, r: T) { l = r }


/*  This test is what prompted me to make CatList and Battle (defined below), due
    to the verbose / inflexibility of this code:
*/
test1: do {

  print("Test1: No Battle struct or CatList struct:")
  var mittens = Cat(newCatWithName: "Mittens")
  var nyan    = Cat(newCatWithName: "Nyan")

  mittens ->> mittens.fireRocket(at: nyan)
  nyan ->> nyan.takeDamage(from: mittens)
  mittens ->> mittens.readyForNextBattle()

  // TODO: Refactor to nyan ->> mittens.FireRocket(at: nyan) to save 2 constructor calls

  assert(nyan.hp == 30, "Failed")
  print ("Nyan HP is 30 after battle:  \(nyan.hp)\n")
}

Second part of code (not as important; attempts to make Test1 better):

/* List of Cats: */

/// Holds our cats:
struct CatList {

  // TODO: Enum.case.rawValue seemed too verbose in the constructor, but Enum would be ideal..
  struct Names { static let fluffy="Fluffy", kitty="Kitty", boots="Boots"}

  // Known cats:
  let fluffy: Cat,
      kitty:  Cat,
      boots:  Cat

  // Unknown cats (random battles):     // TODO: Implement random battles with unnamed cats
  let uk_cats: [Cat]

  // Default: // TODO: Make singleton:
  private init(defaults: Int) {
    fluffy = Cat( newCatWithName:        Names.fluffy )
    kitty  = Cat( copyCat: fluffy, name: Names.kitty  )
    boots  = Cat( copyCat: kitty , name: Names.boots  )

    uk_cats = []                        // TODO: Something with this..
  }

  // Add named cats here:
  init(copyCatList ccl: CatList, fluffy: Cat? = nil, kitty: Cat? = nil, boots: Cat? = nil, uk_cats: [Cat]? = nil) {
    fluffy  == nil ? (self.fluffy  = ccl.fluffy)  : (self.fluffy  = fluffy! )
    kitty   == nil ? (self.kitty   = ccl.kitty)   : (self.kitty   = kitty!  )
    boots   == nil ? (self.boots   = ccl.boots)   : (self.boots   = boots!  )
    uk_cats == nil ? (self.uk_cats = ccl.uk_cats) : (self.uk_cats = uk_cats!)
  }
}


/* Global: */

/// Instance to pass around:
var gCatList: CatList


/* Battle funk */

/** Static / abstract struct (func only):

    gCatList = Battle.start(handleResults(doCombat()))
*/
struct Battle {

  /// 1v1 Combatants:
  typealias Combatants = (attacker: Cat, victim: Cat)


  /// Makes doCombat (defined next) more Englishy / fun, by pairing an enum to a 1v1 Cat.method()
  enum Attacks {

    case fires1Rocket

    func becomeFunc(combatants: Combatants) -> ()->(Cat) {

      let attacker = combatants.attacker
      let victim   = combatants.victim

      switch self {
        case fires1Rocket:
          return { attacker.fireRocket( at: victim) }
      }
    }
  }


/** Returns two new cats after battling.. Use them to update your CatList:

    results = doCombat()
*/
  private static func doCombat(attacker: Cat, _ atk_const: Attacks, at victim: Cat)
    -> Combatants {

    // Because we need to need execute the attack:
    let attacker2: ()->(Cat)     = atk_const.becomeFunc((attacker, victim))

    // Returners (Cats):
    let that_attacked:       Cat = attacker2().readyForNextBattle()
    let that_was_victimized: Cat = victim.takeDamage(from: attacker2())

    return (attacker: that_attacked, victim: that_was_victimized)
  }


/** Mutates our gCatList automagically with the battle results:

    updated_cat_list = handleResults()
*/
  private static func handleResults(battled_cats battled_cats: Combatants,
                                   fromInitial   list:        CatList)
    -> CatList {

    // Returner method:
    func matchName(this_cat:         (name: String, is_attacker: Bool),
                   updateFrom list2: CatList
                /* battled_cats:     Combatants */)
      -> CatList {

        // Returner:
        let new_cat: Cat

        // Logic1:
        this_cat.is_attacker ?
          (new_cat = battled_cats.attacker) : (new_cat = battled_cats.victim)

        // Logic2:
        typealias n=CatList.Names
        switch this_cat.name {
          case n.boots:  return CatList (copyCatList: list2, boots:  new_cat)
          case n.fluffy: return CatList (copyCatList: list2, fluffy: new_cat)
          case n.kitty:  return CatList (copyCatList: list2, kitty:  new_cat)
          default: fatalError("cant find cat's name. Should use an Enum")
        }
    }

    // Returners:
    let attacker2 = (name: battled_cats.attacker.name, is_attacker: true)
    let victim2   = (name: battled_cats.victim.name  , is_attacker: false)

    // Attacker must present 'dmg_to_give' to victim;
    // therefore, attacker must be processed first (on the right):
    return matchName( victim2, updateFrom: (matchName(attacker2, updateFrom: list)) )
  }


/** Brings all private funcs together (in reverse order):

#### usage:
    gCatList = (start -> handleResults -> doCombat)

- NOTE:
 Reads from global in default pram for convenience (no mutate):
*/
  static func start(combatants:            Combatants,
                    initialList gcat_list: CatList = gCatList)
    -> CatList {

      let attacker = combatants.attacker
      let victim   = combatants.victim

      return handleResults(battled_cats: doCombat( attacker, .fires1Rocket, at: victim ),
                           fromInitial:  gcat_list)
  }
}

Final testing:

/* TESTING: 2-4 */

// Tests 2 - 4. Fluffy is the Victim
aBattleTests: do {

  let victim_hp  = "Victim's HP after battle (should be 30): "
  let assertHP30 = { assert(gCatList.fluffy.hp == 30, "Failed") }

  test2: do {

    // Most verbose way (but has most clarity / readability):
    print("Test2: Verbose Battle Struct:")
    gCatList = CatList(defaults: 1)

    let test_attacker      = gCatList.boots
    let test_victim        = gCatList.fluffy
    let between_combatants = (test_attacker, test_victim)
    gCatList->>Battle.start(between_combatants)

    assertHP30()
    print(victim_hp, gCatList.fluffy.hp, "\n")
  }

  test3: do {

    // Verbose way:
    print("Test3: ")
    gCatList = CatList(defaults: 1)
    gCatList->>Battle.start((attacker: gCatList.boots, victim: gCatList.fluffy))

    assertHP30()
    print(victim_hp, gCatList.fluffy.hp, "\n")
  }

  test4: do {

    // Least verbose way: (force error)
    print("Test4: Assertion Failure:")
    gCatList = CatList(defaults: 0)
    gCatList->>Battle.start((gCatList.boots, gCatList.boots))

    assertHP30()
    print(victim_hp, gCatList.fluffy.hp, "\n")
  }
}

I found that a better way might be to just do something like:

nyan = fluffy.attack(victim: nyan)

The above would get rid of 2 constructor calls... But the main point of this program was to test the general idea of default prams in constructors, not necessarily the most efficient way to battle with cats.

Also, using nil as a default pram in the initializer is SUPER slow. It's a lot faster (but more verbose) to use a regular init that's called through a makeNewCat(copyCat: Cat) -> Cat function (about 4 times faster)...

It's starting to look like to me that any code that has heavy mutation simply is going to be much faster with final class X { var xField: Type; func mutateX() }, as it scales at almost f(x) = 1 compared to 1:1 scaling with initializer transformations (more fields = slower performance).

TLDR:

Right now, I'm leaning towards mutability for the heavy-hitters in GamePlay code (players, enemies, etc), and immutability for things like assignment logic / algorithms.

I haven't found a fast enough way (within say 20% of final class) to transform a data set (20-50 fields), and the scaling issues are absolutely tragic. Dictionaries are supposed to be super fast, so perhaps struct isn't the way to go (outside of a namespace for everything for caching reasons).

Granted, things in SpriteKit / SceneKit etc are already NSObjects and are slow as crud due to OBJc. I will probably never actually need any of this performance I'm crying about. Just where I'm at right now.

\$\endgroup\$
  • 1
    \$\begingroup\$ One thing I will say that could potentially make this code better: use Swift's mutating for structs. The structure is still immutable, but then Swift handles the copy/assign for you. That, and it's time to update to Swift 3 😊 If I have time I'll come give this a more detailed review: it looks interesting. \$\endgroup\$ – CAD97 Nov 22 '16 at 18:50
  • \$\begingroup\$ @CAD97 What do you mean with mutating? Switching the fields to var and having a mutating method? Thanks for reading :) \$\endgroup\$ – Fluidity Nov 22 '16 at 19:22
  • \$\begingroup\$ Exactly that. It may not be perfectly FP but it's Swifty. Here's a discussion of implications with a link to a talk. \$\endgroup\$ – CAD97 Nov 22 '16 at 19:25
  • \$\begingroup\$ @CAD97 You can't have mutability with a let instance, regardless of the func type, with struct. The talk was specifically about using what I've written :) stateless code that returns a new instance. Or maybe I'm missing what you're saying.. Perhaps an example :)? Thanks for your time. PS, thanks for the link! I've read the organizers books but wasn't aware of the conferences :) \$\endgroup\$ – Fluidity Nov 22 '16 at 20:06
6
+50
\$\begingroup\$

First, let me get out of the way that I'm not a "Functional Programmer", and I probably won't ever be. I'm also not an "Object-Oriented Programmer", or any other paradigm. I tend to use whatever the language most lends itself to and what others are doing, and what fits the bill.

On that note, to the actual review! I'm only going through First Test for now.

In the beginning, there was code.

There are several potential improvements to code clarity available even before considering the approach that you take to object design.

->>

I do not see the point of including the ->> operator (even though it looks cool because I use a ligature font), as it just is =. lhs ->> rhs === lhs = rhs in your code.

Furthermore, according to this R manual page, these are the assignment operators:

x <- value
x <<- value
value -> x
value ->> x

This would mean that, if you were following the convention from R, you should write mittens.fireRocket(at: nyan) ->> mittens to assign the return from Cat::fireRocket to mittens. To further that, the double angle bracket arrows search through parent scopes to find the variable, which is definitely not what is happening here. If you really want to use arrow assignment, you should probably use lhs <- rhs as lhs = rhs, in this case.

You could potentially be following operators from a different Functional Language, but in this case I would favor just using =, as it's already in the language and anyone will understand it without having to look up your custom operator definition.

??, the Null Coalescing Operator

These lines:

age     == nil   ?  (self.age     = cc.age)     : (self.age     = age!    )
name    == nil   ?  (self.name    = cc.name)    : (self.name    = name!   )
rockets == nil   ?  (self.rockets = cc.rockets) : (self.rockets = rockets!)
// etc

can be greatly simplified using the Null Coalescing Operator (Swift 2.2), ??:

self.age     = age     ?? cc.age
self.name    = name    ?? cc.name
self.rockets = rockets ?? cc.rockets
// etc.

init

Naming:

  • Cat(newCatWithName:) -> Cat(name:)
  • Cat(copyCat:) -> Cat(copyOf:)

Additionally, it's generally considered bad form to have initializers have a side effect, such as printing to STDOUT.

Purity

A comment in your code suggests that methods cannot be pure because they are functions which implicitly take a parameter self. Though it is valid to think about methods as a function with a implicit self, it is more correct to think of the method actually running "in" (or "on", depending on who you ask) the containing object, and self is just a way to reference it.

In any case, methods can be pure, by any useful definition, as they don't have to modify self. An impure function is one that has a side effect by mutating state, and it doesn't matter what is available to it. In fact, in a Swift struct, a method must be pure over self if it does not have the mutating keyword.

Make status an enum

But for the point of succinctness, I won't here.

Checkpoint

At this point, test1 looks like this:

print("Test 1")
var mittens = Cat(name: "Mittens")
var nyan    = Cat(name: "Nyan")

mittens = mittens.fireRocket(at: nyan)
nyan = nyan.takeDamage(from: mittens)
mittens = mittens.readyForNextBattle()

Then, there was the function.

Let's try going full Functional, shall we? Disclaimer: I do not recommend writing Swift this way in a shared code base, as Swift is usually used more like in the third section, below, but this section exists as an exercise into purely Functional Swift.

Functional code means functions which operate on data.

First, let's define our data type, Cat:

struct Cat {
    let rockets, lives, hp: Int
    let name, status: String
    let AP = 40, DEF = 20, hpMAX = 50
    init(name: String) { /* implementation */ }
    init(copyOf: Cat, rockets: Int? = nil, /* etc */) { /* implementation */ }
}

Now what operations do we want to do? A rocket is fired from one Cat to another Cat. What is the result of this operation? The state of the cats afterwards.

func fireRocket(from: Cat, to: Cat) -> (Cat, Cat)

Returning a Tuple allows us to use one step to transform the data. fireRocket might be implemented like so:

func fireRocket(from attacker: Cat, to receiver: Cat) -> (Cat, Cat) {
    let damageDone = attacker.AP - receiver.DEF
    let attackerAfter = Cat(copyOf: attacker, rockets: attacker.rockets - 1)

    let died = receiver.hp > damageDone
    let hp = died ? receiver.hp - damageDone : receiver.hpMAX
    let lives: Int? = died ? receiver.lives - 1 : nil
    let status: String? = died ? "Dead" : nil
    let receiverAfter = Cat(copyOf: receiver, hp: hp, lives: lives, status: status)

    return (attackerAfter, receiverAfter)
}

(Full source of FULL FUNCTIONAL here)

Checkpoint

Here's Test 1 with this code:

print("Test 1")
var mittens = Cat(name: "Mittens")
var nyan    = Cat(name: "Nyan")
(mittens, nyan) = fireRocket(from: mittens, to: nyan)

though even here we should be using immutable data for Full Functional.

In the end, there was compromise.

Truly, I believe in the best of both worlds. However, especially performance wise, I believe in the power of playing to your language's strengths.

In Swift, this means mutating structs. Mutating structs are still immutable data structures. It's just that these two calls are identical1:

struct Immutable {
    let state: Int
    func madeBetter() -> Immutable {
        return Immutable(state: state * 2)
    }
}
let imm = Immutable(state: 5).madeBetter()

/* ***** */

struct Mutable {
    var state: Int
    mutating func makeBetter() {
         state *= 2
    }
}
var mut = Mutable(state: 5)
mut.makeBetter()

The key point here is that, if you have a let x: Mutable, you cannot mutate it. mutating func allows you to define a way to apply an operation to immutable state as if it were mutable state.

So, what does the mutating struct look like?

struct Cat {
    var name:    String,
        rockets: Int,
        lives:   Int,
        status:  String,
        hp:      Int

    let AP    = 40,
        DEF   = 20,
        MAXHP = 50

    init(name: String) {
        self.name = name
        self.rockets = 5
        self.lives = 9
        self.hp = MAXHP
        self.status = "Alive"
    }

    mutating func fireRocket(inout at victim: Cat) {
        let damage = self.AP - victim.DEF
        self.rockets -= 1

        victim.hp -= damage
        if victim.hp <= 0 {
            victim.hp = victim.MAXHP
            victim.lives -= 1
            victim.status = victim.lives > 0 ? "Alive" : "Dead"
        }
    }
}

Checkpoint

Test 1:

print("Test1: No Battle struct or CatList struct:")
var mittens = Cat(name: "Mittens")
var nyan    = Cat(name: "Nyan")

mittens.fireRocket(at: &nyan)

assert(nyan.hp == 30, "Failed")
print("Nyan HP is 30 after battle: \(nyan.hp)")
print()

In my humble opinion, this reads the best of all the options, and Swift emphasizes the syntax at the call site. The & says "hey, this gets modified", and mittens is firing the rocket, not having the rocket fired from them. But hey, I'm "Not a Functional Programmer™"

Postlude: consider using class anyway

Since you mention this is in a game environment and you are concerned about performance: consider using class. Paraphrased from Apple's docs:

Use class when it makes sense for two different scopes to refer to the same object. Use struct in all other cases, as its pass-by-value semantics are safer.

Expensive resources should be shared. The more data you need to lug around, the more important it is that you don't need to make copies of it any time you want to work with it.

And as a final note, reflect on the difference between these four things:

  • immutable struct: Unchanging data, pass by value
  • immutable class: Unchanging data, pass by reference
  • mutable struct: Changing data, pass by value
  • mutable class: Changing data, pass by reference

These two characteristics should be why you choose one over the other, not some adherence to a paradigm.


1: at a semantic level. The underlying implementation of the latter may use more aggressive non-copying optimizations when an old copy is discarded.

\$\endgroup\$
  • \$\begingroup\$ whew, that took longer than expected. \$\endgroup\$ – CAD97 Nov 23 '16 at 3:10
  • \$\begingroup\$ FfFfFff im just now seeing this. i thought nobody answered :( Ill try to contact moderator about bounty.. \$\endgroup\$ – Fluidity Nov 27 '16 at 6:33
  • \$\begingroup\$ the nil coalesce was amazing. im in disbelief that I didnt recognize to do that there \$\endgroup\$ – Fluidity Nov 27 '16 at 6:45
  • \$\begingroup\$ ive already decided to use mutable state for such things, but i picked up a good many tips here. my main goal is to make good code, and that certainly for me at least means NOT adhering to paradigms from any crowd. Ive decided to do whatever keeps me in the debugger/tester the least... and thus far minimizing mutability and referential transparency has been doing it for me... but for things that are updated every frame, final class or mutable struct is the clear answer... but you can bet your boots that my save file models are let / let structs. \$\endgroup\$ – Fluidity Nov 27 '16 at 7:01
  • 2
    \$\begingroup\$ Very nice answer! We'll get the bounty sorted out, one way or another. Don't forget it next time @Fluidity ! \$\endgroup\$ – janos Nov 30 '16 at 7:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.