Swift playground and LeetCode OJ - swift

class Solution {
func reverseString(s: String) -> String {
let rev = String(s.characters.reverse())
print(rev)
}
}
The error i get is:
Missing return in a function expected to return String
The same function in Leetcode OJ gives me the following error:
Line 4: cannot call value of non-function type 'Distance' (aka 'Int')
While i type the following in the Playground it works fine:
var str = "Hello"
let rev = String(str.characters.reverse())
I can't seem to figure out the solution to this and why it behaves differently in the playground with the function return type and in Leetcode OJ.
Swift noob and any help would be most appreciated! thanks

Try this:
class Solution {
func reverseString(s: String) -> String {
let rev = String(s.characters.reverse())
print(rev)
return rev
}
}
var str = Solution()
str.reverseString("Hello")
If you intend to add custom methods which works on a a particular Type than create an extension on that Type type.
extension String {
// you methods
}
For example:
extension String {
func length() -> Int {
return self.characters.count
}
}
Then you can use it as class function on String type
let greetings: String = "Hello"
greetings.length() // 5

Related

How do I get the value of a Published<String> in swift without using debugDescription?

I've got the following code, that runs in a playground.
I'm attempting to allow subscript access to #Published variables in a class.
The only way I've found so far to retrieve the String value in the below implementation of
getStringValue
is to use the debugDescription, and pull it out -- I've looked at the interface for Published, but can't find any way to retrieve the value in a func like getStringValue
Any pointers would be greatly appreciated :)
Edited to include an example of how it works with a non-published variable.
Cheers
import Foundation
import Combine
protocol PropertyReflectable {}
extension PropertyReflectable {
subscript(key: String) -> Any? {
return Mirror(reflecting: self).children.first { $0.label == key }?.value
}
}
class Foo : PropertyReflectable {
#Published var str: String = "bar"
var str2: String = "bar2"
}
// it seems like there should be a way to get the Published value without using debugDescription
func getStringValue(_ obj: Combine.Published<String>?) -> String? {
if obj == nil { return nil }
let components = obj.debugDescription.components(separatedBy: "\"")
return components[1]
}
let f = Foo()
let str = getStringValue(f["_str"] as? Published<String>)
print("got str: \(str!)")
// str == "bar" as expected
let str2 = f["str2"]!
print("got non-published string easily: \(str2)")
Published seems to be steeped in some compiler magic, for lack of a better wording, since it can only be used as a property wrapper inside classes.
That being said, would something like this work?
final class PublishedExtractor<T> {
#Published var value: T
init(_ wrapper: Published<T>) {
_value = wrapper
}
}
func extractValue<T>(_ published: Published<T>) -> T {
return PublishedExtractor(published).value
}

Returning the associatedtype of an opaque return type

I have a simple protocol with an associated type, and a protocol extension that returns an array of this type.
protocol Foo {
associatedtype Unit
}
extension Foo {
var allTheFoos: [Unit] {
return []
}
}
I then have a struct which returns some Foo in a computed property, and another computed property that returns the allTheFoos array.
struct FakeFoo: Foo {
typealias Unit = Int
}
struct FooFactory {
var myFoo: some Foo {
return FakeFoo()
}
/* WHICH RETURN TYPE WILL
PLEASE THE SWIFT GODS?!
*/
var allTheFoos: [Foo.Unit] {
return myFoo.allTheFoos
}
}
The return type of allTheFoos matches Xcode's autocomplete type suggestion for the myFoo.allTheFoos call, but understandably, this yields a:
// var allTheFoos: [Foo.Unit] {}
ERROR: Associated type 'Unit' can only be used with a concrete type or generic parameter base
My question is: What return type will make Xcode happy?
Below are my attempts, and their corresponding errors
// var allTheFoos: [some Foo.Unit] {}
ERROR: 'some' types are only implemented for the declared type of properties and subscripts and the return type of functions
// func allTheFoos() -> some [Foo.Unit]
ERROR: Associated type 'Unit' can only be used with a concrete type or generic parameter base
// func allTheFoos<U: Foo.Unit>() -> [U]
ERROR: Associated type 'Unit' can only be used with a concrete type or generic parameter base
ERROR: Cannot convert return expression of type '[(some Foo).Unit]' to return type '[U]'
// func allTheFoos<U>() -> [U] where U: (some Foo).Unit
ERROR: 'some' types are only implemented for the declared type of properties and subscripts and the return type of functions
FYI: The reason I'm doing this in a computed property in the first place is to keep things clean in some SwiftUI code.
Thanks for any help you can give!
=========== UPDATE ===========
I missed some important stuff in my sample code, so to give some context: the code is used in a unit conversion app, so something that can turn Celsius into Kelvin, Kg into lbs, and anything else into anything else.
protocol Unit: Equatable {
var suffix: String { get }
}
struct Value<UnitType: Unit> {
let amount: Double
let unit: UnitType
var description: String {
let formatted = String(format: "%.2f", amount)
return "\(formatted)\(unit.suffix)"
}
}
Value is constrained to a unit type, so that it's not possible to convert Celsius into Litres.
Therefore, we have a Conversion protocol that stores all similar units together:
protocol Conversion {
associatedtype UnitType: Unit
var allUnits: [UnitType] { get }
func convert(value: Value<UnitType>, to unit: UnitType) -> Value<UnitType>
}
extension Conversion {
func allConversions(for value: Value<UnitType>) -> [Value<UnitType>] {
let units = self.allUnits.filter { $0 != value.unit }
return units.map { convert(value: value, to: $0) }
}
}
So an example of a conversion for Temperature would be:
struct Temperature: Conversion {
enum Units: String, Unit, CaseIterable {
case celsius, farenheit, kelvin
var suffix: String {
switch self {
case .celsius: return "˚C"
case .farenheit: return "˚F"
case .kelvin: return "K"
}
}
}
var allUnits: [Units] { return Units.allCases }
func convert(value: Value<Units>, to unit: Units) -> Value<Units> {
/* ... */
}
}
Finally, the actual app code where the problem occurs is here:
struct MyApp {
var current: some Conversion {
return Temperature()
}
// ERROR: Associated type 'UnitType' can only be used with a concrete type or generic parameter base
var allConversions: [Value<Conversion.UnitType>] {
// This value is grabbed from the UI
let amount = 100.0
let unit = current.allUnits.first!
let value = Value(amount: amount, unit: unit)
return current.allConversions(for: value)
}
}
Looking at how you've implemented AnyValue, I think what you want here is just:
var allConversions: [String] {
let units = self.allUnits.filter { $0 != value.unit }
return units.map { convert(value: value, to: $0) }.description
}
Or something like that. All the algorithms that match what you're describing are just "conversion -> string." If that's the case, all you really want is CustomStringConvertible.
Managed to solve this issue using some Type Erasure:
struct AnyValue {
let description: String
init<U: Unit>(_ value: Value<U>) {
self.description = value.description
}
}
allowing for:
var allConversions: [AnyValue] {
// This value is grabbed from the UI
let amount = 100.0
let unit = current.allUnits.first!
let value = Value(amount: amount, unit: unit)
return current.allConversions(for: value).map(AnyValue.init)
}
However, this feels like a clunky solution (and one that opaque return types was introduced to avoid). Is there a better way?

How to create an extension of the Swift struct JoinedSequence?

I need to create a wrapper around the function joined(separator:) and I think the best way is to create an extension of the JoinedSequence struc where the original function is declared.
So i wrote this sample code:
extension JoinedSequence {
func joinWithComma() -> String {
return joined(separator: ", ")
}
}
unfortunately doesn't work because "Ambiguous reference to member 'joined()'".
The joinWithComma should work with a sequence of CustomStringConvertible and should return a String
This could be what you want:
extension Sequence where Iterator.Element == String {
public func joinWithComma() -> String {
return joined(separator: ", ")
}
}
var arr = ["1", "2"]
arr.joinWithComma() // output: "1, 2"
Looking at the Array documentation of its joined(separator: String = default) -> String method , says this:
And if you tried to use JoinedSequence for this purpose, the new method extension wouldn't get to the Array.
extension JoinedSequence where Base.Iterator.Element.Iterator.Element == String {
public func joinWithComma() -> String {
return joined(separator: ", ")
}
}
var arr = ["1", "2"]
arr.joinWithComma()
// Compiler error: Value of type '[String]' has no member 'joinWithComma'
NOTE: This is my own observation about this, probably someone more experienced could tell exactly the explanation about this problem.

Swift subscript setter that accepts a different type than the getter's return value

I have a custom collection that can receive values of any type and converts them to strings. For example:
collection["key"] = 10
let value = collection["key"] // value is a String
Is there a way to do this? I tried implementing two subscript methods but Swift doesn't support write-only subscripts.
subscript(key: String) -> String {
get { ... }
}
// Doesn't compile
subscript(key: String) -> AnyObject {
set { ... }
}
You can use two different subscript implementations and disable the getter for one of them:
subscript(key: String) -> String {
get { return "howdy" } // put real implementation here
}
subscript(key: String) -> AnyObject {
get { fatalError("Oooops") }
set { }
}
However, this still leaves open the question of how to distinguish between these two subscript calls in context. It would be better to give them different signatures through their external parameter names:
subscript(key: String) -> String {
get { return "howdy" } // put real implementation here
}
subscript(# any: String) -> AnyObject {
get { fatalError("Oooops") }
set { }
}
And here's how to use it:
let m = MyClass()
m[any:"thing"] = 1
println(m["thing"]) // "1", presumably
Define subscript to return AnyObject (or Any as needed) and at the point you use the getter cast the result to String. You may already need to deal with subscript returning an optional so the coercion is just all part of extracting your desired value.
if let value = collection["key"] as String { ... }
else {...}
You could also define your own type and make it conform to the IntegerLiteralConvertible and the StringLiteralConvertible protocols.
Technically you could also write an extension for String to make it conform to IntegerLiteralConvertible but that might get confusing, since it will be available in your entire project.
I was facing a similar problem here and I solved it using a generic type for my variable and returning the type I want on its getter. You can try doing something like this:
class StorageClass {
private var _value: String?
public var value: Any? {
set {
if let num = newValue as? Int {
self._value = String(format: "%d",num)
}
}
get {
return self._value
}
}
}
By doing this, it is possible to do something like:
var storage = StorageClass()
storage.value = 10 /* setting value as an Integer */
let aString = storage.value as! String /* receiving a String value back */

Automatic Type Conversion with extension: What is happening here?

I'm going through the first chapter of The Swift Programming Language book and I'm at the part where it's describing the extension keyword.
I had a go at the "Experiment":
“Write an extension for the Double type that adds an absoluteValue property.”
I got it working like this:
extension Double {
var absoluteValue: Double {
if(self < 0) {
return self * -1
}
return self
}
}
(-10.5).absoluteValue // 10.5
But it also seems to work for integers:
(-4).absoluteValue // 4.0
What is happening here? Is the compiler changing the type from Int to Double because it sees that there is a absoluteValue extension on Double but not Int?
This appears to be the case because if I add another extension of the same name on Int like so:
extension Int {
var absoluteValue: Int {
return 42
}
}
That overrides the extension on Double. And (-4).absoluteValue returns 42
Is there a way to add an extension that only works on Doubles but not Ints?
Edit: Looks like it's doing a conversion at compile-time and since I didn't define a type for my literal it converted it. The following produces an error
var i:Int = -4;
i.absoluteValue
"Playground execution failed: error: :12:1: error: 'Int' does not have a member named 'absoluteValue'
i.absoluteValue
^ ~~~~~~~~~~~~~"
Edit 2: It appears to only apply to literals; the following also produces an error:
var i = -4;
i.absoluteValue
Yes, the extension you wrote is actually only for Doubles, not for Ints. Take a look at this example:
extension Double {
var absoluteValue: Double {
if (self < 0) {
return self * -1
}
return self
}
}
var double: Int = 10
double.absoluteValue // Int does not have a member named absoluteValue
But, in your code the compiler is implicitly converting your Int to a Double.
In case anyone would like an answer that conforms to the example protocol:
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
extension Double: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
var absoluteValue: Double {
return fabs(self)
}
mutating func adjust() {
self = round(self)
}
}
var double: Double = -12.34
double.simpleDescription
double.absoluteValue