How to match statuscode with an Int in Scala - scala

What would be a good way in Scala to match an integer with Status codes defined in Akka-http:
I would like to do something like:
if (passedErrorCodeToMethod == 200) {
complete(ToResponseMarshallable(StatusCodes.OK -> errorResponse))
}
else if (passedErrorCodeToMethod == 400) {
complete(ToResponseMarshallable(StatusCodes.BadRequest -> errorResponse))
}
But I obviously don't want to do this for all error codes and would rather like to have this be done via pattern matching or in a more scalable way

StatusCodes.getForKey(passedErrorCodeToMethod) match {
case Some(status) => complete(status -> errorResponse)
case None => oopsie()
}
Something like this ?

Related

Can you (now? Swift5?) write "if case" as a boolean when determining an enum's associated type?

Say you need to determine the actual associated type of an enum.
So, a situation like
enum MessageItem: Decodable {
case a(Images)
case b(Text)
case c(Reply)
...
}
I used to have code like this
xSome = x.filter {
switch $0 {
case .a(_):
return false
case .b(_):
return true
case .c(_):
return true
}
}
But then it was possible to have code like this
xSome = x.filter {
if case .a = $0 { return false }
return true
}
Is there now some way it Swift to compare against associated type producing a boolean?
So, something like:
xSome = x.filter {
return (case .a = $0)
}
So, something like anEnum.is( .someCase )
Is anything like this now in Swift?
(Naturally, I mean without adding a var in the enum, which of course you can do.)
Enums with associated values are equatable if you declare them Equatable. Here's the state of play:
enum MyEnum : Equatable {
case hey
case ho
case heyNonnyNo(String)
}
let e = MyEnum.hey
e == .hey // true
e == .ho // false
// e == .heyNonnyNo // blap, illegal
let e2 = MyEnum.heyNonnyNo("hello")
e2 == .heyNonnyNo("hello") // true
e2 == .heyNonnyNo("goodbye") // true
Why is e == .heyNonnyNo illegal? Because it's unclear what it can mean. This case has an associated value; its value is the associated value. So we can check whether two instances of this case have the same associated value, but we can't just ask (using ==) whether an instance is some associated value of this case.
So if that's what we want to know, we are back to if case:
if case .heyNonnyNo = e2 {
print("it's a hey nonny no")
}
But you can't say that without if (for use in a conditional) because if case is the keyword; case can't exist by itself. If you really need a Bool, you could write it out like this:
let ok : Bool = {
switch e2 {
case .heyNonnyNo: return true
default: return false
}
}()

What's the best way to handle invalid arguments in scala

I'm writing a function that takes a request object, there are several ways that the request could be configured, but only one valid form, so before I perform my function I'd like to test how the object is configured. If I were doing this in java, I'd write something like this:
static void func(Request request) {
if (condition1)
return false
if (condition 2)
return false
if (condition 3)
return false
request.process()
return true
}
In scala though, in trying to avoid using return, I usually end up with this:
static void func(Request request) {
if (!condition1) {
if (!condition 2) {
if (!condition 3) {
request.process()
return true
}
else
return false
}
else
return false
}
else
return false
}
This is a simplified form as usually there are things that I need to do after condition 1, and then after condition 2, which mean that I can't just combine the conditions into a single if statement (e.g. condition 1 checks that something isn't null, then condition 2 checks if the value of that thing is valid).
What I'm wondering is how do I make my code clean and readable whilst still having these checks in place?
you can use pattern matching
request match {
case _ if (condition1 || condition2 || condition3) => false
case _ => request.process(); true
}
In Scala it is usual to return Option[value] rather than returning true/false and relying on side effects. And a Request object would normally be pure data, with processing done by an external function.
So a typical Scala function might look like this:
def func(req: Request): Option[Result] =
req match {
case Request(a, _, _) if condition1(a) => None
case Request(_, b, _) if condition2(b) => None
case _ =>
Some(processRequest(req))
}
You can just do a simple if else simplifying your conditions.
def func(request: Request) {
if (condition1 || condition2 || condition3)
false
else {
request.process()
true
}
}

Swift 3 enum with associated value AND function comparison

I have this struct that has an enum property as well as a function:
struct UserInput {
enum State {
case unrestricted
case restricted(because: WarningType)
enum WarningType {
case offline
case forbidden
}
}
var config: UserInputConfig?
var state: State = .unrestricted
func isConfigured() -> Bool {
// Arbitrary checks about the config...
}
}
Is there a way to rewrite the following conditionals so that the check for isConfigured() and state are in the same statement?
if case .restricted = userInput.state {
return 1
} else if userInput.isConfigured() {
return 1
} else {
return 0
}
It seems because the State enum uses associated values, you cannot simply write if userInput.state == .restricted || userInput.isConfigured(), you need to use the if case syntax. There must be a way around this?
You would like to do this:
if case .restricted = userInput.state || userInput.isConfigured() {
return 1
} else {
return 0
}
but there is currently no way to do an OR with pattern matching. There are a couple of ways of doing AND.
By using DeMorgan's Laws, you can turn if a || b into if !(!a && !b) and by reversing the then and else clauses of your if statement, you can just check for if !a && !b.
Unfortunately, you can't say if !(case .restricted = userInput.state), but since your enum has only 2 cases, you can replace that with if case .unrestricted = userInput.state.
Now, how do you use that with another statement? You can't use && for the same reason you can't use ||.
You can check for the failing case by using a pattern that matches both failing conditions (which is using AND) and then return 1 if both failing conditions aren't met:
if case (.unrestricted, false) = (userInput.state, userInput.isConfigured()) {
return 0
} else {
return 1
}
Equivalently you can use a multi-clause condition:
if case .unrestricted = userInput.state, !userInput.isConfigured() {
return 0
} else {
return 1
}
In addition to being shorter and IMO easier to read, this second method can short circuit and skip calling userInput.isConfigured in the case where case .unrestricted = userInput.state fails.
You can do it really cleanly with a switch statement, and pattern matching:
switch userInput.state
{
case .unrestricted:
return userInput.isConfigured() ? 1 : 0;
case .restricted(_):
return 1
}

Pattern matching negation

How can I negate pattern matching in Swift?
For example I want to do something like:
guard case .wait != currentAction.type else {
return
}
But apparently, I can't. I can do this:
if case .wait = currentAction.type {
return
}
but it's less Swifty. Is there a better way?
Apparently, there is no way to do that right now as of Swift 3.
Things can change in future releases.
You can do this in Swift 3.0.2:
guard currentAction.type != .wait else {
return
}

How to compare one value against multiple values - Swift

Let's say that you have the code
if stringValue == "ab" || stringValue == "bc" || stringValue == "cd" {
// do something
}
Is there a way to shorten this condition or beautify it (preferably without using the switch statement)? I know that this code does NOT work:
if stringValue == ("ab" || "bc" || "cd") {
// do something
}
I've seen some complex solutions on other languages, but they seem language specific and not applicable to Swift. Any solutions would be appreciated.
let valuesArray = ["ab","bc","cd"]
valuesArray.contains(str) // -> Bool
You can create an extension like this:
extension Equatable {
func oneOf(other: Self...) -> Bool {
return other.contains(self)
}
}
and use it like this:
if stringValue.oneOf("ab", "bc", "cd") { ... }
Credit for the impl which saved me typing it: https://gist.github.com/daehn/73b6a08b062c81d8c74467c131f78b55/
Not that i am aware, you can do something like this though,
let validStrings = Set<String>(arrayLiteral:"ab", "bc", "cd")
if validStrings.contains(str) {
//do something
}
Use a Switch Statement.
switch stringValue {
case "ab", "bc", "cd":
print("Yay!")
default:
break
}
The construction ["some", "array"].contains("value") works, but is somewhat annoying:
It inverts the left-to-right order you may want to write.
Items in the array are not declared using Swift's type inference, often forcing you to include unnecessary information to please the compiler.
You can instead use Set(["value"]).isSubset(of: ["some", "array"]).
The benefit is especially apparent when working with enums:
enum SomeReallyReallyLongTypeName {
case one, two
}
struct Thing {
let value: SomeReallyReallyLongTypeName
}
let thing = Thing(value: .one)
if Set([thing.value]).isSubset(of: [.one, .two]){
// :)
// Left-to-right order
// You get nice type inference
}
if [SomeReallyReallyLongTypeName.one, .two].contains(thing.value) {
// :(
// Annoying to have "SomeReallyReallyLongTypeName" in the code
}
if someArray.contains(object) {
// contains
} else {
// does not contains
}
The above function returns bool value, then you write logic accordingly.
Just for fun, how about overloading functions over String:
if a.isOneOf("ab", "bc", "cd") {
print("yes")
}
extension String {
#inlinable
func isOneOf(_ first: String, _ second: String) -> Bool {
self == first || self == second
}
#inlinable
func isOneOf(_ first: String, _ second: String, _ third: String) -> Bool {
self == first || isOneOf(second, third)
}
#inlinable
func isOneOf(_ first: String, _ second: String, _ third: String, _ fourth: String) -> Bool {
self == first || isOneOf(second, third, fourth)
}
}
This gives you full performance benefits, as the compiler will be able to inline and tail call as much as it wants, at the cost of having to write as many overloads as you need in your code, and also not being able to pass arrays - but other answers deal with this too.
let a = 1
let b = 1
let c = 1
let d = 1
if a == b,a==c,a==d {
print("all of them are equal")
}
else {
print("not equal")
}