Named arguments allows the caller to specify some subset of arguments it wants to call.
This PR introduce a syntax for callers inspired from the Python one (the Ruby one uses columns that clashes with types declaration).
~~~nit
format(linewidth=80, separator=":", indent=true)
~~~
The specification tries to be as simple as possible
* Only default parameters can be passed by name; because the other are mandatory.
This restriction is also useful to avoid to specify additional rules, like the last parameter of assignment methods, because the ones on default arguments apply.
~~~nit
fun foo(a,b: nullable Int) do ...
foo(b=1)
foo(null,1) # equivalent
~~~
* Named arguments can appear anywhere (not necessarily at the end)
~~~nit
fun foo(a: Int, b: nulable Int)
foo(b=1,2)
foo(2,1) # equivalent
~~~
* The order of evaluation is the order of the arguments (not the order of the parameters).
I think this is more POLA this way.
* The names to use are the one of the statically designated method declaration (not the introduction).
This one is problematic because the language permit the name of parameters to change in redefinitions.
But in case of errors or in a IDE it is often more useful to point the most precise method definition.
The implementation was trivial because the hard work was already done in the previous PR.
This PR was unlocked by #1280
Pull-Request: #1281
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Etienne M. Gagnon <egagnon@j-meg.com>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>
Theses services are implemented using the POSIX threads.
You can also use the `is threaded` annotation on methods, which makes them run on their own thread.
-Methods with return value or self calls are not supported.
+Methods with self calls are not supported.
+
+A method or function annotated with `is threaded` has its return value changed during compilation.
+You will get a subclass of `Thread`, even if there wasn't a return value before. You can know if the threaded method is done with the `is_done` boolean from `Thread`.
+A call to the `join` method will block the execution until the threaded method is done, or immediatly return if it's already done.
+`join` will return an object typed with the orginial return type, or `null` if there wasn't.
## Known limitations:
* See: `man pthreads`
* See: `examples/concurrent_array_and_barrier.nit`
+* See: ̀ examples/threaded_example.nit`
print s
end
+# Parameterized `threaded` method with a return type
+fun baz(i : Int, j : Int): Int is threaded do
+ sys.nanosleep(10, 0)
+ return i + j
+end
+
+print "main"
foo
bar(10, "parameterized and threaded")
-print "main"
sys.nanosleep(5,0)
+var x = baz(2, 3)
+print "main, waiting for baz"
+var y = x.join
+print("baz result : " + y.to_s)
abstract class Thread
super Finalizable
+ # Type returned by `main`
+ type E : nullable Object
+
private var native: nullable NativePthread = null
+ # Is this thread finished ? True when main returned
+ var is_done = false
+
# Main method of this thread
#
# The returned valued is passed to the caller of `join`.
- fun main: nullable Object do return null
+ fun main: E do return null
- private fun main_intern: nullable Object
+ private fun main_intern: E
do
# Register thread local data
sys.self_thread_key.set self
-
- return main
+ var r = main
+ self.is_done = true
+ return r
end
# Start executing this thread
# `Sys::thread_exit`. Returns the object returned from the other thread.
#
# Stats the thread if now already done by a call to `start`.
- fun join: nullable Object
+ fun join: E
do
if native == null then start
var r = native.join
native = null
- return r
+ return r.as(E)
end
redef fun finalize
#TODO: check for self calls
- if nmethdef.n_signature.n_type != null then
- toolcontext.error(nat.location, "Error: functions not supported yet.")
- return
- end
-
# Get the module associated with this method
var amod = nmethdef.parent.parent
assert amod isa AModule
classname += nmethdef.n_methid.as(AIdMethid).n_id.text
end
+ # Handle methods with a return value
+ var has_rvalue = nmethdef.n_signature.n_type != null
+ var vtype = ""
+ if has_rvalue then
+ vtype = "redef type E: " + nmethdef.n_signature.n_type.n_id.text
+ end
+ # create a return type
+ var n_id = new TClassid
+ n_id.text = classname
+ var n_type = new AType
+ n_type.n_id = n_id
+ nmethdef.n_signature.n_type = n_type
var params = new Array[String]
# case if the method has parameters
class {{{classname}}}
super Thread
+ {{{vtype}}}
+
{{{params.join("\n")}}}
redef fun main do
end
mainfun.n_block = nmethdef.n_block
# Add "return null" to the end of the `main` function
- var s_nullreturn = "return null"
- var nullreturn = toolcontext.parse_something(s_nullreturn)
- assert nullreturn isa AExpr
- mainfun.n_block.as(ABlockExpr).n_expr.add(nullreturn)
-
+ if not has_rvalue then
+ var s_nullreturn = "return null"
+ var nullreturn = toolcontext.parse_something(s_nullreturn)
+ assert nullreturn isa AExpr
+ mainfun.n_block.as(ABlockExpr).n_expr.add(nullreturn)
+ end
# Create new body for the annotated fun
var s_newbody : String
s_newbody ="""
var thread = new {{{classname}}}({{{init_params.join(",")}}})
thread.start
+return thread
"""
else
s_newbody = """
var thread = new {{{classname}}}
thread.start
+return thread
"""
end
threaded
10
parameterized and threaded
+main, waiting for baz
+baz result : 5