Question about type hinting in Python 3.9+ - type-hinting

I have a method that takes a callback function as an argument.
I want to specify a type hint for the callback function signature.
The problem is the signature of the callback function is:
def callback_function(event, token, *args)
where
type(event) = EventClass
type(token) = str
type(args) = tuple # of str
I could write this as:
callable[[...], returntype]
but I would like to tighten the type checking to be something useful, at least to making sure event and token are specified correctly.
Suggestions, please?

Consider using Protocol for this matter, as answered before.
For your specific case it will look like this:
from typing import Protocol, TypeAlias
returntype: TypeAlias = int
class MyCallable(Protocol):
def __call__(self, event: EventClass, token: str, *args: str) -> returntype: ...
def some_function(callback: MyCallable): ...

Related

Partials functions as parameters and function parameter annotation

Suppose we have a function that receives a callable as parameter:
def foo(bar: Callable[[Any], Any]) -> None:
pass
According the annotation the callable we must pass as argument should receive only one argument and return anything, just like:
def third_party_callable(x: Any) -> None:
pass
But we have our own callable that receives 2 arguments so we decide to use functools.partial to match the foo signature:
def my_custom_callable(y: Any, x: Any) -> None:
pass
my_callable = partial(my_custom_callable, 'my_custom_y')
# And then ...
foo(my_callable)
This will result in a linter warning stating that: Expected type '(Any) -> None', got 'partial[None]' instead
Question 1: Is there some way to do this and not getting the linter warning?
Question 2: Should the returned type of partial be Callable[[...], ...]?
Question 3: If what I want is not a desired behavior could someone explain why?

How to send a type parameter as a function argument

I caught myself repeatedly using a similar piece of code for JSON unmarshalling. The only difference between the snippets was the type parameter in a function call. Consequently, I tried to write a function to improve code reuse, but I cannot seem to get it to compile. What I'm attempting to do is shown below.
/** Decode a GET response by unmarshalling its JSON payload.
* #tparam R The type of Response to unmarshall into.
* #param response The GET response to decode.
* #return Try[R] if decoding was successful, else Failure[Throwable] */
private def decodeResponse[R <: Response](response: HttpResponse): Try[R] = {
val payload = decode[R](response.text)
logger.debug(s"Decoded payload: $payload")
payload.toTry
}
As you can see, I wish to specify a type R as part of my return type and part of my function body. I believe it is the latter which is causing compilation to fail, but I am unsure of how to fix it. An example of an R would be SearchResponse, the case class definition for which extends the Response trait.
I've performed several searches into type parameters, but no results use type parameters in function bodies. Additionally, I've searched for the exception that is being thrown upon compilation:
Error:(72, 28) could not find implicit value for evidence parameter of type io.circe.Decoder[R]
val payload = decode[R](response.text)
However, all results lead to solutions for specific libraries that caused these problems, which unfortunately isn't of use for me. Any help would be appreciated!
The decode[R] function requires an implicit parameter of type Decoder[R]. To make your code compile, you need to add this implicit parameter to your own function:
private def decodeResponse[R <: Response](response: HttpResponse)(implicit decoder: Decoder[R]): Try[R] = …
Passing an implicit parameter Foo[A] for some type parameter A is a very common occurrence, which is why they came up with a terser syntax for this use case: Context bounds.
https://docs.scala-lang.org/tutorials/FAQ/context-bounds.html
All it means is that when you write this
def foo[A: Foo] = …
it will be equivalent to this:
def foo[A](implicit f: Foo[A])

Is it possible in scala to have a generic method taking a method as an argument?

I would like to have:
def myMethod[T < ???](f: T): Unit = {
f()
}
The rest of the method is not really important but is it possible to replace ??? by somethind which would make sure T is a method
and if possible to go even further and make sure the return type of T is something defined ?
Like [T < (_*) => Int]
Thank you.
Would defining a type, like in the following trivial example, address your need?
type Fcn = String => Int
def myMethod(s: String, f: Fcn): Unit = {
println(f(s))
}
myMethod("hello", (s: String) => s.length)
// 5
You can use function literals:
def myMethod[A, T](f: A => T) {
f(someAValue)
}
or if you want functions that take no arguments:
def myMethod[T](f: () => T) {
f()
}
But judging by your comments, it seems like you specifically want to reference methods, and query the method for information about itself, which is not a feature of basic Scala. You may be able to do some of that with reflection, but reflection is an area best avoided.
Technically, you can't directly pass a method, since a method is not a value that you can instantiate and pass-around. What is usually passed around is a function instance. And when it appears that you're passing a method, the compiler is actually creating a function instance for you (method lifting or eta-expansion).
But that is not going to work if you're looking to inspect meta data about that method (name, deprecation). For that, you're probably looking for reflection. You can have your method take an instance of java.reflect.Method but that will require that you obtain that at call-site.

Scala map cannot resolve mapper function

Scala noob here.
I'm trying to apply a map in a class method:
class Miner(args: Args) extends Job(args) {
def fetchUrl(url:String) = {
...
}
TextLine(args("input")).map(url: String => fetchUrl(url))
.write(args("output"))
}
this codes breaks complaining about not being able to resolve the symbol fetchUrl.
I've thought that, fetchUrl being a one argument function, I could just omit the argument and do something like:
TextLine(args("input")).map(fetchUrl)
.write(args("output"))
This now breaks saying that I'm missing arguments for the method fetchUrl.
What gives?
Isn't mapTo a curried function?
I imagine you use this function from this object: (google redirects me to that)
mapTo[U](out: Fields)(mf: (String) ⇒ U)(implicit flowDef: FlowDef, mode: Mode, setter: TupleSetter[U]): Pipe
Perhaps you would use it like this: Textline.mapTo(args("input"))(fetchUrl)
You have some examples of mapTo usage at this page, but based on the Pipe object:
https://github.com/twitter/scalding/wiki/Fields-based-API-Reference#map-functions
Excerpt:
val savings =
items.mapTo(('price, 'discountedPrice) -> 'savings) {
x : (Float, Float) =>
val (price, discountedPrice) = x
price - discountedPrice
}
So not based on TextLine in this example, but also curried...this might be a good hint for you.

How to define a method in Scala that returns a Java object?

I want to define a private method in scala singleton class that looks like;
private def createDomNode(tag: String, attrs: Map[String , String]): DomNode {
}
DomNode is Java type, not scala type. attrs is scala Map with both key and value being of type String.
But above gives error. What is the correct format?
Thanks Easy Angel for the answer. There is still some confusion. According to Programming in Scala book written by the inventor of the language, the below is a function:
def max(x: Int, y: Int): Int = {
if (x > y) x
else y
}
But your answer says it is method and not function. Can you kindly explain?
What is REPL?
You should just put =:
private def createDomNode(tag: String, attrs: Map[String , String]): DomNode = {
// ...
}
If you will not put = between method signature and body, then return type is Unit, so this:
def m(i: Int) {}
is the same as
def m(i: Int): Unit = {}
Response to the comment: What I described earlier is actually method, if you define it within object, class or trait definition. Function syntax would look like this:
val createDomNode: (String, Map[String , String]) => DomNode = { (tag, attrs) =>
// ...
}
As You can see I define val with name createDomNode of function type. It can also be written like:
val createDomNode: Function2[String, Map[String , String], DomNode] = { (tag, attrs) =>
// ...
}
here is another example. In this case I define method that generates new function each time you call it:
def createDomNode = (tag: String, attrs: Map[String , String]) => new DomNode
But it's important to understand, that method returns a "function that returns DomNode" in this case, but not DomNode itself.
About Programming in Scala reference. I think you are talking about Chapter 2 - Step 3 (in the intro)
As you can see max function is defined in REPL, and it's really function. Actually you can also write something like this:
class MyClass {
def myMethod(i: Int): Int = {
def myInnerFn(x: Int) = x * x
myInnerFn(i)
}
}
In this case myMethod is method and myInnerFn is function. So as you can see, it highly depends on the context. I believe this syntax for myInnerFn is just syntactic sugar for (I need to look in spec in order to say for sure):
val myInnerFn = (x: Int) => x * x
The same happens in REPL. And by the way that's because I wrote at the beginning:
if you define it within object, class or trait definition
Sorry, I need to be more clear about this and describe it in more detail in my second update.
I looked in Scala spec. Seems that I'm not totally correct when I say that myInnerFn is syntactic sugar for the function. but seems that it's called Method Type. You can find it in spec section 3.3.1 Method Type:
http://www.scala-lang.org/docu/files/ScalaReference.pdf
hope it will give you some clue, if you want to dive deeper in this. I think it's easy to get lost in terminology. You can function in 2 contexts. In first we have
Function - returns some value
Procedure - returns no value (or in Scala context it returns Unit)
And in second context:
Function - executable piece of code that can be passes around and treated as value
Method - belongs to the class
And it's sometimes not clear in what context it meant. For example I can tell you that myMethod is as function just because it has return value (or in other words: myMethod it's not procedure). I believe it's the same case in book.
One more thing. Sections 8.1, 8.2, 8.3 from Programming in Scala can help you to understand this terminology. And if I'm correct in my assumptions, what you think as Function is called First-class function in the book (it's described in section 8.3).
Hope this helps