Is there a way to "replicate" this feature found in other languages?

In another langage I used in the past there was a very handy feature :slight_smile:

Sub myRoutine(somevar as String, assigns new_value as string)
  newValue=somevar + new_value
End Sub

which would be used like this

myRoutine("foo")="bar"

with the result being "foobar"

I have tried to come up with some func/class/structure that would allow me to replicate this.

The best option would be Computed Property where you could pass arguments

var myRoutine(somevar : String) : String {
    get { return backingStore }
    set { backingStore = "\(somevar)\(newValue)"
}

"Computed Property where you could pass arguments" is, roughly, a custom subscript:

struct S {
    private var store: [String: String] = [:]

    subscript(_ key: String) -> String {
        get { return store[key] ?? "" }
        set { store[key] = key + newValue }
    }
}

var s = S()

s["foo"] = "bar"
print(s["foo"]) // 'foobar'

Does that accomplish what you're trying to do?

Well, yes and no... that would work in the exact example I provided
but not when the func has a more complex signature

var myRoutine(var1 : String, var2 : Int, var3 : Double) : String {
    get { return <something> }
    set { < do something with var1, var2, var3 AND newValue )
}
 subscript(var1 : String, var2 : Int, var3 : Double) -> String {
         get { return <something> }
    set { < do something with var1, var2, var3 AND newValue )
    }

but it DOES seem you can have the above signature... so THAT might work

1 Like

Yep, it's perfectly valid for subscripts to take multiple arguments!

Thanks let me experiment.... would be nice if I didn't have to create a structure, then an instance of it.

This is part of a project to actually translate code from That other language into Swift... and that ONE feature has so far been a sticking point... I have 95% of the rest working

Looks like this syntax will work in my Translator

Before

Sub myRoutine(var1 as String, var2 as Double, assigns Xyz as integer)
// do stuff
End sub

After

var myRoutine = _myRoutine()

struct _myRoutine {
	subscript(_ var1: String,_ var2 : Double) -> Int? {
		get { return nil }
		set { var xyz = newValue!
			// do stuff
		}
	}
}

Seems like a good use for callAsFunction.

not familiar... can you provide a simple example?

struct Appender {
    var value = "initialValue "
    
    mutating func callAsFunction(_ string: String) {
        value = value + string
    }
}

var appender = Appender()

appender("secondValue")

print(appender.value) // Prints "initialValue secondValue"

You can read more around the internet, like this post.

thanks but that doesn't meet the requirement of having the "newValue" on the right of the assignment

the required syntax would need to end up

appender = "secondvalue"

note that any use would be a non-value returning function

You can also use a static subscript to eliminate instantiation:

enum myRoutine {
    static subscript(_ var1: String,_ var2 : Double) -> Int? {
        get { return nil }
        set { var xyz = newValue!
            // do stuff
        }
    }
}

Thanks, I will try that variation as well...

Seems like that works :)
BASIC code going into my Translator*

private Sub myRoutine(var1 as String, var2 as Double, assigns Xyz as integer)
   var x as integer =3
   print(x)
End sub

Swift code coming out

import Cocoa
private enum myRoutine {
   subscript(_ var1 : String , _ var2 : Double) -> Int? {
      get { return nil }
      set { let Xyz = newValue!
      let x : Int = 3
      print(x)
   }  
}  
}

THANKS... the took my translator another major step forward

Enum version doesn't work.... cannot assign values
but Struct version seems to

You can use the enum in the static case, as it ensures you can’t creat an instance. They don’t have mutable instance properties.

Well this works except inside an Extension, any ideas? or cannot it not be done?


extension String {
	struct myRoutine  {
		subscript (_  var2 : String) -> Int? {
			get { return nil }
			set { let Xyz = newValue!
				let x : Int = 3
				print("\(Xyz) \(x) \(self)")
			}
		}
	}
}
func test() {
	print("test")
	var s : String = ""
	s.myRoutine["A"] = 3  // <--------------- ERROR
	// Instance member 'subscript' cannot be used on type 'String.myRoutine'
	// Static member 'myRoutine' cannot be used on instance of type 'String'
}



// Defining as a FUNC replacement only, works just fine

private var myRoutine2 = _myRoutine2()
struct _myRoutine2 {
	subscript (_  var1 : String ,_  var2 : String) -> Int? {
		get { return nil }
		set { let Xyz = newValue!
			let x : Int = 3
			print("\(Xyz) \(x) \(var1) \(var2)")
		}
	}
}
func test2() {
	print("test2")
	myRoutine2["A" , "B"] = 3
}

Which do you want: s.myRoutine["A"] = 3 (where s: String), String.myRoutine["A"] = 3 or myRoutine["A"] = 3?

Your first example fails because you are defining something which would be used as: String.myRoutine()["A"] = 3 and calling it as s.myRoutine["A"] = 3

well I wanted

s.myRoutine["A"] = 3 

which I guess doesn't work, as the Struct needs to be instantiated

You can do either this:

extension String {
    subscript (myRoutine var2: String) -> Int? {
        get { return nil }
        nonmutating set { print("\(self) \(var2) \(newValue!)") }
    }
}
func test1() {
    let s = "B"
    s[myRoutine: "A"] = 3
}
test1() // prints B A 3

Or this:

extension String {
    struct _MyRoutine {
        var parent: String
        subscript (_  var2: String) -> Int? {
            get { return nil }
            nonmutating set { print("\(parent) \(var2) \(newValue!)") }
        }
    }
    var myRoutine: _MyRoutine { _MyRoutine(parent: self) }
}
func test2() {
    let s = "B"
    s.myRoutine["A"] = 3
}
test2() // prints B A 3