Skip to content
Closed
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ New language features
and macros in packages and user code ([#8791]). Type `?@doc` at the repl
to see the current syntax and more information.

* Varargs functions may now declare the varargs length as `x::Vararg{T,N}` to
restrict dispatch.

Language changes
----------------

Expand Down
2 changes: 2 additions & 0 deletions base/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ call(T::Type{WeakRef}, v::ANY) = Core.call(T, v)

call{T}(::Type{T}, args...) = convert(T, args...)::T

typealias NTuple{N,T} Tuple{Vararg{T,N}}

convert{T}(::Type{T}, x::T) = x

convert(::Type{Tuple{}}, ::Tuple{}) = ()
Expand Down
2 changes: 1 addition & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#abstract Any <: Any
#abstract Type{T}

#abstract Vararg{T}
#abstract Vararg{T,N}
#Tuple = (Any...)

#type Symbol
Expand Down
1 change: 1 addition & 0 deletions base/datafmt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module DataFmt

importall Base
import Base: _default_delims, tryparse_internal
import Base: NTuple

export countlines, readdlm, readcsv, writedlm, writecsv

Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export
MathConst,
Matrix,
MergeSort,
NTuple,
Nullable,
ObjectIdDict,
OrdinalRange,
Expand Down
4 changes: 2 additions & 2 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ const getfield_tfunc = function (A, s0, name)
if !isa(s,DataType)
return Any
end
if is(s.name,NTuple.name)
return s.parameters[2]
if s <: Tuple && s.types.length == 1 && isvatuple(s)
return s.types[1].parameters[1]
end
if s.abstract
return Any
Expand Down
16 changes: 14 additions & 2 deletions base/methodshow.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Method and method-table pretty-printing

function argtype_decl(n, t) # -> (argname, argtype)
if isvarargtype(t)
return argtype_decl_vararg(n, t)
end
if isa(n,Expr)
n = n.args[1] # handle n::T in arg list
end
Expand All @@ -12,14 +15,23 @@ function argtype_decl(n, t) # -> (argname, argtype)
if t === Any && !isempty(s)
return s, ""
end
if isvarargtype(t)
return s, string(t)
end

function argtype_decl_vararg(n, t)
s = string(n.args[1])
if n.args[2].head == :...
# x... or x::T... declaration
if t.parameters[1] === Any
return string(s, "..."), ""
else
return s, string(t.parameters[1], "...")
end
end
return s, string(t)
# x::Vararg, x::Vararg{T}, or x::Vararg{T,N} declaration
s, length(n.args[2].args) < 4 ?
string("Vararg{", t.parameters[1], "}") :
string("Vararg{", t.parameters[1], ",", t.parameters[2], "}")
end

function arg_decl_parts(m::Method)
Expand Down
1 change: 1 addition & 0 deletions base/multidimensional.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module IteratorsMD
import Base: eltype, length, start, done, next, last, getindex, setindex!, linearindexing, min, max, eachindex
import Base: simd_outer_range, simd_inner_length, simd_index, @generated
import Base: @nref, @ncall, @nif, @nexprs, LinearFast, LinearSlow, to_index
import Base: NTuple

export CartesianIndex, CartesianRange

Expand Down
1 change: 1 addition & 0 deletions base/sparse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ importall Base.LinAlg
import Base.promote_eltype
import Base.@get!
import Base.Broadcast.eltype_plus, Base.Broadcast.broadcast_shape
import Base.NTuple

export AbstractSparseArray, AbstractSparseMatrix, AbstractSparseVector, SparseMatrixCSC,
blkdiag, dense, droptol!, dropzeros!, etree, issparse, nnz, nonzeros, nzrange,
Expand Down
2 changes: 2 additions & 0 deletions doc/manual/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@ the zero or more values passed to ``bar`` after its first two arguments:
In all these cases, ``x`` is bound to a tuple of the trailing values
passed to ``bar``.

It is possible to constrain the number of values passed as a variable argument; this will be discussed later in :ref:`man-vararg-fixedlen`.

On the flip side, it is often handy to "splice" the values contained in
an iterable collection into a function call as individual arguments. To
do this, one also uses ``...`` but in the function call instead:
Expand Down
26 changes: 26 additions & 0 deletions doc/manual/methods.rst
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,32 @@ can also constrain type parameters of methods::
The ``same_type_numeric`` function behaves much like the ``same_type``
function defined above, but is only defined for pairs of numbers.

.. _man-vararg-fixedlen:

Parametrically-constrained Varargs methods
------------------------------------------

Function parameters can also be used to constrain the number of arguments that may be supplied to a "varargs" function (:ref:`man-varargs-functions`). The notation ``Vararg{T,N}`` is used to indicate such a constraint. For example:

.. doctest::

julia> bar(a,b,x::Vararg{Any,2}) = (a,b,x)

julia> bar(1,2,3)
ERROR: MethodError: `bar` has no matching method bar(::Int, ::Int, ::Int)

julia> bar(1,2,3,4)
(1,2,(3,4))

julia> bar(1,2,3,4,5)
ERROR: MethodError: `bar` has no method matching bar(::Int, ::Int, ::Int, ::Int, ::Int)

More usefully, it is possible to constrain varargs methods by a parameter. For example::

function getindex{T,N}(A::AbstractArray{T,N}, indexes::Vararg{Number,N})

would be called only when the number of ``indexes`` matches the dimensionality of the array.

Note on Optional and keyword Arguments
--------------------------------------

Expand Down
2 changes: 2 additions & 0 deletions src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ typedef struct {
// Note that this function updates len
static jl_value_t *jl_new_bits_internal(jl_value_t *dt, void *data, size_t *len)
{
/*
if (jl_is_ntuple_type(dt)) {
jl_value_t *lenvar = jl_tparam0(dt);
jl_value_t *elty = jl_tparam1(dt);
Expand All @@ -119,6 +120,7 @@ static jl_value_t *jl_new_bits_internal(jl_value_t *dt, void *data, size_t *len)
memcpy(jl_data_ptr(v), data, nb);
return v;
}
*/

assert(jl_is_datatype(dt));
jl_datatype_t *bt = (jl_datatype_t*)dt;
Expand Down
167 changes: 166 additions & 1 deletion src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1263,7 +1263,7 @@ void jl_init_primitives(void)
add_builtin("TypeName", (jl_value_t*)jl_typename_type);
add_builtin("TypeConstructor", (jl_value_t*)jl_typector_type);
add_builtin("Tuple", (jl_value_t*)jl_anytuple_type);
add_builtin("NTuple", (jl_value_t*)jl_ntuple_type);
// add_builtin("NTuple", (jl_value_t*)jl_ntuple_type);
add_builtin("Vararg", (jl_value_t*)jl_vararg_type);
add_builtin("Type", (jl_value_t*)jl_type_type);
add_builtin("DataType", (jl_value_t*)jl_datatype_type);
Expand Down Expand Up @@ -1617,6 +1617,171 @@ DLLEXPORT void jl_(void *jl_value)
in_jl_--;
}

// Useful because the jl_typeof macro isn't available from debugger
void jl_static_show_typeof(JL_STREAM *out, jl_value_t *v)
{
if (v == NULL) {
jl_printf(out, "#<null>");
}
else if (jl_typeof(v) == NULL) {
jl_printf(out, "<?::#null>");
}
else if (jl_astaggedvalue(v)->type_bits < 4096U) {
jl_printf(out, "<?::#%d>", (int)jl_astaggedvalue(v)->type_bits);
}
else if (jl_is_lambda_info(v)) {
jl_printf(out, "lambda_info");
}
else if (jl_is_svec(v)) {
jl_printf(out, "svec");
}
else if (jl_is_datatype(v)) {
jl_printf(out, "DataType");
}
else if (jl_is_func(v)) {
jl_printf(out, "#<function>");
}
else if (jl_typeis(v, jl_intrinsic_type)) {
jl_printf(out, "#<intrinsic function>");
}
else if (jl_is_int64(v)) {
jl_printf(out, "Int64");
}
else if (jl_is_int32(v)) {
jl_printf(out, "Int32");
}
else if (jl_typeis(v,jl_int16_type)) {
jl_printf(out, "Int16");
}
else if (jl_typeis(v,jl_int8_type)) {
jl_printf(out, "Int8");
}
else if (jl_is_uint64(v)) {
jl_printf(out, "UInt64");
}
else if (jl_is_uint32(v)) {
jl_printf(out, "UInt32");
}
else if (jl_typeis(v,jl_uint16_type)) {
jl_printf(out, "UInt16");
}
else if (jl_typeis(v,jl_uint8_type)) {
jl_printf(out, "UInt8");
}
else if (jl_is_cpointer(v)) {
jl_printf(out, "cpointer");
}
else if (jl_is_float32(v)) {
jl_printf(out, "Float32");
}
else if (jl_is_float64(v)) {
jl_printf(out, "Float64");
}
else if (v == jl_true || v == jl_false) {
jl_printf(out, "jl_boolean");
}
else if (v == jl_nothing) {
jl_printf(out, "nothing");
}
else if (jl_is_byte_string(v)) {
jl_printf(out, "ByteString");
}
else if (jl_is_uniontype(v)) {
jl_printf(out, "Union");
}
else if (jl_is_typector(v)) {
jl_printf(out, "TypeConstructor");
}
else if (jl_is_typevar(v)) {
jl_printf(out, "TypeVar");
}
else if (jl_is_module(v)) {
jl_printf(out, "Module");
}
else if (jl_is_symbol(v)) {
jl_printf(out, "Symbol");
}
else if (jl_is_gensym(v)) {
jl_printf(out, "GenSym");
}
else if (jl_is_symbolnode(v)) {
jl_printf(out, "SymbolNode");
}
else if (jl_is_globalref(v)) {
jl_printf(out, "GlobalRef");
}
else if (jl_is_labelnode(v)) {
jl_printf(out, "LabelNode");
}
else if (jl_is_gotonode(v)) {
jl_printf(out, "GotoNode");
}
else if (jl_is_quotenode(v)) {
jl_printf(out, "QuoteNode");
}
else if (jl_is_newvarnode(v)) {
jl_printf(out, "NewVarNode");
}
else if (jl_is_topnode(v)) {
jl_printf(out, "topnode");
}
else if (jl_is_linenode(v)) {
jl_printf(out, "LineNode");
}
else if (jl_is_expr(v)) {
jl_printf(out, "Expr");
}
else if (jl_is_array(v)) {
jl_printf(out, "Array");
}
else if (jl_typeis(v,jl_loaderror_type)) {
jl_printf(out, "LoadError");
}
else if (jl_typeis(v,jl_errorexception_type)) {
jl_printf(out, "ErrorException");
}
else if (jl_is_datatype(jl_typeof(v))) {
jl_datatype_t *dv = (jl_datatype_t*)jl_typeof(v);
if (dv->name->module != jl_core_module) {
jl_static_show_x(out, (jl_value_t*)dv->name->module, 0);
jl_printf(out, ".");
}
jl_printf(out, "%s", dv->name->name->name);
if (dv->parameters && (jl_value_t*)dv != dv->name->primary) {
size_t j, tlen = jl_nparams(dv);
if (tlen > 0) {
jl_printf(out, "{");
for (j = 0; j < tlen; j++) {
jl_value_t *p = jl_tparam(dv,j);
jl_static_show_x(out, p, 0);
if (j != tlen-1)
jl_printf(out, ", ");
}
jl_printf(out, "}");
}
else if (jl_is_tuple_type(dv)) {
jl_printf(out, "{}");
}
}
}
else {
jl_printf(out, "<?Unknown?>");
}
}

DLLEXPORT void jlt_(void *jl_value)
{
in_jl_++;
JL_TRY {
(void)jl_static_show_typeof(JL_STDOUT, (jl_value_t*)jl_value);
jl_printf(JL_STDOUT,"\n");
}
JL_CATCH {
jl_printf(JL_STDOUT, "\n!!! ERROR in jlt_ -- ABORTING !!!\n");
}
in_jl_--;
}

DLLEXPORT void jl_breakpoint(jl_value_t *v)
{
// put a breakpoint in you debugger here
Expand Down
4 changes: 2 additions & 2 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -1897,7 +1897,7 @@ void jl_init_serializer(void)
jl_labelnode_type, jl_linenumbernode_type,
jl_gotonode_type, jl_quotenode_type, jl_topnode_type,
jl_type_type, jl_bottom_type, jl_ref_type, jl_pointer_type,
jl_vararg_type, jl_ntuple_type, jl_abstractarray_type,
jl_vararg_type, /*jl_ntuple_type, */jl_abstractarray_type,
jl_densearray_type, jl_box_type, jl_void_type,
jl_typector_type, jl_typename_type,
jl_task_type, jl_uniontype_type, jl_typetype_type, jl_typetype_tvar,
Expand All @@ -1910,7 +1910,7 @@ void jl_init_serializer(void)
jl_datatype_type->name, jl_uniontype_type->name, jl_array_type->name,
jl_expr_type->name, jl_typename_type->name, jl_type_type->name,
jl_methtable_type->name, jl_method_type->name, jl_tvar_type->name,
jl_ntuple_type->name, jl_abstractarray_type->name, jl_vararg_type->name,
/*jl_ntuple_type->name, */jl_abstractarray_type->name, jl_vararg_type->name,
jl_densearray_type->name, jl_void_type->name, jl_lambda_info_type->name,
jl_module_type->name, jl_box_type->name, jl_function_type->name,
jl_typector_type->name, jl_intrinsic_type->name, jl_task_type->name,
Expand Down
Loading