42
\$\begingroup\$

Using your language of choice, write a function that takes a variable number of arguments and returns the number of arguments it was called with.

Specifics:

  • Your language needs to support variadic argument functions: something callable that takes an arbitrary number of arguments and returns a value.
  • Parameters must be able to be passed individually. This means that passing an array would only count for one parameter. You can use an "all passed arguments" array if your language supports it; the restriction is on how the function is called.
  • Code that calls this function must not be required to pass the number of arguments in its source. If a compiler inserts the number of arguments as part of a calling convention, that is allowed.
  • The arguments can be of any type you want. You can support only a single type (e.g. only supporting int is still valid), arbitrary types (any type of argument is allowed), or any combination of argument types (e.g. first arg is int, rest are strings).
  • Your function may have a maximum number of arguments (especially since resources are finite), but must support at least 2 arguments.

Samples:

  • f() returns 0
  • f(1) or f("a") returns 1
  • f([1, 2, 3]) returns 1 as it is passed an array, not 3 arguments
  • f(1, 10) or f(1, "a") returns 2

As this is code-golf, the winning solution is the one that uses the fewest number of bytes.

caird coinheringaahing
50.9k11 gold badges133 silver badges364 bronze badges
asked Apr 10, 2018 at 3:00
\$\endgroup\$
21
  • 6
    \$\begingroup\$ It's not entirely clear (objectively) what is a "function", "return value" or "variadic arguments". For example, would Dodos function be considered as monadic or variadic? \$\endgroup\$ Commented Apr 10, 2018 at 5:06
  • 28
    \$\begingroup\$ @user202729 If your language doesn't support functions, use another language. It's not a requirement that all languages can compete, part of code golfing is finding the right tool for the job. \$\endgroup\$ Commented Apr 10, 2018 at 7:46
  • 5
    \$\begingroup\$ @user202729 I have no problems with the occasional challenge aimed at traditional/high-level languages, just as we have the occasional challenge that is only possible in unusual languages. \$\endgroup\$ Commented Apr 10, 2018 at 13:58
  • 7
    \$\begingroup\$ didn't know we had to solve the halting problem for language characteristics to have a clear challenge.... \$\endgroup\$ Commented Apr 11, 2018 at 2:06
  • 6
    \$\begingroup\$ If your language doesn't have the concept of arguments / calling convention then it doesn't fit the criteria of supporting arbitrary numbers of arguments. \$\endgroup\$ Commented Apr 11, 2018 at 8:23

81 Answers 81

1
2 3
37
\$\begingroup\$

Java (JDK 10), 11 bytes

a->a.length

Try it online!

answered Apr 10, 2018 at 5:36
\$\endgroup\$
6
  • 33
    \$\begingroup\$ Java beating Javscript is rare enouth to be noticed \$\endgroup\$ Commented Apr 10, 2018 at 7:08
  • 3
    \$\begingroup\$ @Therandomguy this requires something like interface x{void f(Object...a);} to be defined, and this lambda must be either stored in a variable of that interface type, or be passed to a method expecting that interface type, so I'm not really sure it counts for this challenge (even though usually java lambdas are allowed in codegolf challenges) \$\endgroup\$ Commented Apr 10, 2018 at 15:40
  • 5
    \$\begingroup\$ @SamYonnou There is no difference with other lambdas, and as you mentioned, lambdas are fine. \$\endgroup\$ Commented Apr 10, 2018 at 16:15
  • \$\begingroup\$ @OlivierGrégoire I know that lambdas are allowed, my point was that compared to JavaScript for example, you need a lot more extra code to set it up, even if you are using something like REPL and avoid the need for a main class/method (the need for the interface to be defined is what distinguishes it from JavaScript) \$\endgroup\$ Commented Apr 11, 2018 at 18:09
  • 1
    \$\begingroup\$ @PeterCordes That's why the "Try it online" link in my answer exists ;-) \$\endgroup\$ Commented Apr 12, 2018 at 22:43
33
\$\begingroup\$

JavaScript, 15 bytes

[].push.bind(0)

The Array.prototype.push function takes any number of arguments, adds them to its array, and returns the size of the array. Therefore, the push function used on an empty array returns the number of arguments supplied to push.

f = [].push.bind(0)
f(10,2,65,7)
> 4
f()
> 0

The .bind(0) simply gives the push function a fixed this value so that it can be stored in a variable. In fact, the 7-byte identifier [].push can be used literally (but not assigned) without bind:

[].push(10,2,65,7)
> 4
[].push()
> 0
answered Apr 10, 2018 at 14:51
\$\endgroup\$
20
\$\begingroup\$

JavaScript (ES6), 16 bytes

(...a)=>a.length

f=
(...a)=>a.length
console.log(f())
console.log(f(1))
console.log(f(1,2))
console.log(f(1,2,3))
console.log(f(1,2,3,4))

answered Apr 10, 2018 at 3:09
\$\endgroup\$
19
\$\begingroup\$

Haskell, (削除) 108 (削除ここまで) (削除) 107 (削除ここまで) (削除) 95 (削除ここまで) 94 bytes

class T r where z::Int->r
instance T Int where z=id
instance T r=>T(a->r)where z n _=z$n+1
z 0

Try it online!

This was surprisingly hard to get working, but I had fun trying to find out how to implement something that's trivial in imperative languages.

answered Apr 10, 2018 at 7:30
\$\endgroup\$
8
  • \$\begingroup\$ Damn, you beat me to it. f is optional if you say z 0 is the function without the binding, so main = print $ ((z 0) pi 0 () [] :: Int) works. \$\endgroup\$ Commented Apr 10, 2018 at 7:40
  • \$\begingroup\$ And by that I mean that the types work when used as an anonymous function so you can indeed remove everything from the last two rows except z 0 \$\endgroup\$ Commented Apr 10, 2018 at 7:55
  • \$\begingroup\$ Nice, thanks! Turns out I was doing something wrong when I was testing the anonymous function. Tried your example and it worked just fine. \$\endgroup\$ Commented Apr 10, 2018 at 8:07
  • \$\begingroup\$ I guess the ::Int should be counted in the byte count, since the type of the answer has to be declared sooner or later, like in main = print $ ((z 0 :: Double -> Integer -> () -> [a] -> (Int->Int->Int) -> IO () -> Int) pi 0 () [] (+) main). I also think that this works only during compile time so something like foldl(\a b->a b) (z 0) $ [1..5])::Int can't work. Either way, this is great stuff. \$\endgroup\$ Commented Apr 10, 2018 at 11:04
  • 2
    \$\begingroup\$ s/imperative/non-curry/ \$\endgroup\$ Commented Apr 10, 2018 at 15:51
17
\$\begingroup\$

Amstrad CPC Z80 binary call from BASIC, 1 byte, hex encoded

C9 : RET

(Also 2 and 5 byte versions, see below)

Upon entry to the call, the number of parameters passed will be in the A register. The code simply returns immediately. There is no concept of return values in the Z80, just entry and exit states. The value is just "there" accessible in the register since the code changes no input conditions, except for PC (the program counter) and SP (the stack pointer). However, the value in A is not accessible to BASIC and gets overwritten almost immediately.

Examples:

CALL &8000, "Hello", "World"

A = 2

CALL &8000, 42

A = 1

CALL &8000

A = 0


By request, here is some code that makes the value accessible in BASIC. I was very surprised to find it could be done in only 5 bytes!:

The machine code:

12 : LD (DE), A
13 : INC DE
AF : XOR A
12 : LD (DE), A
C9 : RET

On entry:

  • AF - the accumulator and flags registers (treated as two 8-bit registers)
    • A contains the number of parameters passed, up to the maximum of 32 parameters
    • I'm not sure what's in F. It appears to have all flags RESET to 0, except the two undefined flags which are both 1. The Z flag (zero) is SET to 1 if there were no parameters passed in
  • BC
    • B - 32 minus the number of parameters (A + B = 32)
    • C - &FF
  • DE - The address of the last parameter, or the calling address if no parameters were passed in
  • HL - The address of the first byte after the tokenised BASIC command currently being executed (either as a program or in immediate command mode)
  • IX - The stack address of the pointer to the last parameter
  • IY - &0000

The code

  1. LoaDs the address pointed to by DE with the value in A
  2. INCrements DE
  3. XORs A (with A), giving &00
  4. LoaDs the value in A to the address pointed to by DE
  5. RETurns

On exit:

  • A is destroyed (it's always &00)
  • DE is destroyed (it's always one higher than on entry)
  • All other registers are preserved

The BASIC

Amstrad basic has only three data types, plus simple arrays. By default, all BASIC variables are REAL (signed, 32 bit mantissa, 8 bit exponent), which can be made explicit with !. For an INTEGER (signed, 16 bit) use % and for a STRING (1 byte string length, up to 255 bytes character data, binary safe) use $:

  • x - REAL (implicit)
  • x! - REAL (explicit)
  • x% - INTEGER
  • x$ - STRING

You can also use DEFINT, DEFREAL and DEFSTR with a single letter, or a range of two single letters to specify the default type for all variables starting with that letter, similar to FORTRAN.

  • DEFSTR a
  • DEFINT x-z

Now:

  • a - STRING (implicit)
  • i - REAL (implicit)
  • x - INTEGER (implicit)
  • x$ - STRING (explicit)

The easiest type to work with is the integer. The machine code expects the last parameter to passed by address, not value, which is why @ is prefixed to the variable. The return variable is counted as one of the CALLs parameters.

The machine code is called as follows from BASIC (assuming it's loaded at into memory at address &8000):

CALL &8000, "Hello", "World", 42, @n%

n% = 4

This will always give the correct result, regardless of the initial value of n%.

For a 2-byte version that preserves all input registers:

CALL &8003, "Hello", "World", 42, @n%

n% = 4

This skips the first three bytes, and only gives the correct result if the initial value of n% is 0-255. This works because the Z80 is little-endian.

The return parameter must be initialised before being passed, otherwise BASIC will throw an Improper argument error. In the below image, I am printing (with the shortcut ? since I've golfed the demonstration too!) the return values immediately before and after the call to show the value changing. I'm using the value &FFFF because that is the binary representation of -1 for a signed integer. This demonstrates that the 5-byte program correctly writes both bytes, whereas the 2-byte program only writes the low byte and assumes that the high byte is already &00.

enter image description here

answered Apr 10, 2018 at 5:03
\$\endgroup\$
4
  • \$\begingroup\$ So how does the calling convention you're using return values? If it doesn't return them in the accumulator, or at all, then your answer is basically inventing a custom calling convention that solves the problem for you (by adding a return register, instead of passing a pointer where you can store A, if that's how you might actually do it from BASIC). Not that there's anything wrong with that, but it might be a more interesting answer to follow an existing calliing convention. \$\endgroup\$ Commented Apr 12, 2018 at 16:03
  • \$\begingroup\$ @PeterCordes Neither Amstrad BASIC nor the Z80 have the concept of scopes. All values are global and are immediately accessible until destroyed. The value of A is the same immediately after the RET instruction. The lifespan of a value in A is very short since it's the accumulator. There's no such thing as x = CALL &8000, 42. It would have to be CALL &8000, x, 42, and extra Z80 code, but then x would be 2, not 1. \$\endgroup\$ Commented Apr 12, 2018 at 22:26
  • \$\begingroup\$ I think it's fine if you include the output arg in the count, otherwise there's a 1-byte decrement instruction isn't there? I'd be interested to see a version that was actually usable from BASIC instead of being trivial. \$\endgroup\$ Commented Apr 12, 2018 at 22:32
  • 1
    \$\begingroup\$ @PeterCordes Done! Oh, by the way, I forgot to mention not to call it with no parameters as it will overwrite its own first two instructions with &00s - NOP no-ops. Another byte can be added to make it safer, but of course without a return parameter it can't set anything. \$\endgroup\$ Commented Apr 13, 2018 at 13:44
17
\$\begingroup\$

Python 3, 15 bytes

lambda*a:len(a)

Try it online!

answered Apr 10, 2018 at 3:06
\$\endgroup\$
2
  • 6
    \$\begingroup\$ Also, Python 2 :) \$\endgroup\$ Commented Apr 10, 2018 at 3:09
  • \$\begingroup\$ It's not at all surprising that this was the first answer. ;) \$\endgroup\$ Commented Apr 14, 2018 at 3:38
12
\$\begingroup\$

Zsh, (削除) 7 (削除ここまで) 5 bytes

<<<$#

Try it online!

answered Apr 10, 2018 at 4:45
\$\endgroup\$
4
  • \$\begingroup\$ Though it should probably be wrapped: f(){ echo $#; } \$\endgroup\$ Commented Apr 10, 2018 at 7:39
  • 8
    \$\begingroup\$ @muru That looks fine as a full program to me. \$\endgroup\$ Commented Apr 10, 2018 at 8:14
  • \$\begingroup\$ Although, I see now that the OP only wants a function... \$\endgroup\$ Commented Apr 10, 2018 at 15:50
  • 3
    \$\begingroup\$ @Neil shell scripts act exactly like functions. OP doesn't clear on what a function is, I claim my submission is just a function saved to the disk. \$\endgroup\$ Commented Apr 10, 2018 at 17:28
9
\$\begingroup\$

Brain-Flak, 6 bytes

My first Brain-Flak solution worthy posting, I guess it's the right tool for this job:

([]<>)

Try it online!

Explanation

When executing a Brain-Flak program, initially the left stack contains all arguments. From there it's simply a matter of:

( -- push the following..
 [] -- height of the stack (ie. # of arguments)
 <> -- ..to the other stack (toggles to the other stack)
) --
 -- the right stack now contains the # of arguments which
 -- gets printed implicitly
H.PWiz
11.7k2 gold badges23 silver badges57 bronze badges
answered Apr 10, 2018 at 12:26
\$\endgroup\$
8
\$\begingroup\$

Wolfram Language (Mathematica), 11 bytes

Tr[1^{##}]&

Try it online!

Suggested by JungHwan Min. Some restrictions (input must be rectangular) but we are not required to handle arbitrary input.

11 bytes

Length@!##&

Try it online!

Another 11 byte solution suggested by Martin Ender. This seems to error when there isn't one input but it still returns the correct value in all cases.

12 bytes

Length@{##}&

Try it online!

My original solution.

In Mathematica ## stands for a variadic number of arguments in a function. { and } wraps them in a list and Length@ takes the length of this list. & at the end turns this into an actual function.

answered Apr 10, 2018 at 3:47
\$\endgroup\$
0
7
\$\begingroup\$

R, 30 bytes

function(...)length(list(...))

Try it online!

answered Apr 10, 2018 at 6:59
\$\endgroup\$
15
  • 1
    \$\begingroup\$ function(...)nargs() is 20 bytes, but using length(...) was my initial approach until I googled a nargs-like function. \$\endgroup\$ Commented Apr 10, 2018 at 12:15
  • \$\begingroup\$ @Giuseppe hmm, I tried converting the list(...) to a logical so sum() could be used, but that's tricky :/ \$\endgroup\$ Commented Apr 10, 2018 at 12:23
  • 1
    \$\begingroup\$ Haha, don't try and bait me into that argument ;) \$\endgroup\$ Commented Apr 11, 2018 at 8:43
  • 1
    \$\begingroup\$ @RoryT oh actually, R docs say combine. Nevermind :D \$\endgroup\$ Commented Apr 11, 2018 at 8:44
  • 2
    \$\begingroup\$ ...length() does the same thing as length(list(...)) \$\endgroup\$ Commented Apr 17, 2018 at 16:42
7
\$\begingroup\$

Bash, 12 bytes (thanks to paxdiablo for saving 4)

n()(echo $#)

Copy and paste at a bash prompt. Then run the n function from the prompt:

$ n
0
$ n 46 gr 3443 dad
4
$ n 4fwj23 wrw jdwj 00998 34 eyt q3 vg wq j qw
11
answered Apr 10, 2018 at 18:49
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Welcome to PPCG! \$\endgroup\$ Commented Apr 10, 2018 at 18:52
  • \$\begingroup\$ can you just say it is a script "./n" and not a function? then it is just: echo $#, 7 bytes. (will be then any shell you use to launch the "./n" script with. ie, you run bash? then when you: ./n arg1 ... argn it will be interpreted by bash.) \$\endgroup\$ Commented Apr 13, 2018 at 13:04
  • \$\begingroup\$ @Olivier Dulac The challenge clearly says a function. \$\endgroup\$ Commented Apr 13, 2018 at 17:04
7
\$\begingroup\$

C++14 (gcc), 34 bytes

As generic variadic lambda function (C++14 required):

[](auto...p){return sizeof...(p);}

Try it online!

Previous (incorrect) answer: 32 bytes

It was missing the template<class...T> and (p)

int f(T...p){return sizeof...p;}
\$\endgroup\$
5
  • 7
    \$\begingroup\$ C++14, C++11 has no generic lambdas. \$\endgroup\$ Commented Apr 10, 2018 at 12:55
  • 1
    \$\begingroup\$ You could add the permissive flag to be able to remove the parenthesis around p (and -w to turn off the warning). \$\endgroup\$ Commented Apr 10, 2018 at 16:00
  • \$\begingroup\$ @nwp: wouldn't -fpermissive cost you the 12 bytes for that option, though? If it's not standard ISO C++ or GNU C++. \$\endgroup\$ Commented Apr 12, 2018 at 16:05
  • \$\begingroup\$ @PeterCordes It probably does and is intended to avoid having a trivial 0-byte solution for everything by passing the program via command line. I just didn't think about that here because it seems to not be abusive. \$\endgroup\$ Commented Apr 12, 2018 at 16:16
  • \$\begingroup\$ @Quentin fixed -> C++14 \$\endgroup\$ Commented Apr 15, 2018 at 7:15
6
\$\begingroup\$

Octave, 9 bytes

@()nargin

Try it online!

Anonymous function taking any number of arguments (and silently discarding the lot), and outputs the number of arguments through the built-in nargin. This does not work in MATLAB, where you would need varargin to allow for arbitrary many arguments.

answered Apr 10, 2018 at 7:42
\$\endgroup\$
5
\$\begingroup\$

Ruby, 12 bytes

->*a{a.size}

Try it online!

*a is a splat of the arguments, making a consume all arguments passed to the Proc. a.size obtains its size.

answered Apr 10, 2018 at 3:19
\$\endgroup\$
5
\$\begingroup\$

Perl 6, 5 bytes

Thanks @Joshua for -5 bytes

{+@_}

Try it online!

answered Apr 10, 2018 at 4:34
\$\endgroup\$
4
  • \$\begingroup\$ You could just do {+@_} \$\endgroup\$ Commented Apr 10, 2018 at 4:44
  • \$\begingroup\$ @Joshua >_> true, thanks \$\endgroup\$ Commented Apr 10, 2018 at 4:48
  • \$\begingroup\$ You can remove the sub in Perl 6 (not in Perl 5, though). \$\endgroup\$ Commented Apr 10, 2018 at 17:47
  • \$\begingroup\$ @nwellnhof Oh, TIL. Perl 6 is so different from Perl 5 >_> \$\endgroup\$ Commented Apr 11, 2018 at 0:44
4
\$\begingroup\$

C++, 72 bytes

int f(){return 0;}template<class...P>int f(int,P...p){return f(p...)+1;}

Saves bytes by only working with ints.

answered Apr 10, 2018 at 4:30
\$\endgroup\$
1
  • \$\begingroup\$ You can use sizeof.... \$\endgroup\$ Commented Jul 23, 2019 at 4:02
4
\$\begingroup\$

Perl 5, 9 bytes

sub{~~@_}

Try it online!

answered Apr 10, 2018 at 3:48
\$\endgroup\$
4
  • \$\begingroup\$ A quick sitewide search of answers seems to indicate that you can leave out the sub \$\endgroup\$ Commented Apr 10, 2018 at 5:53
  • 2
    \$\begingroup\$ Protip: TIO let's you copy in PPCG post format (ESC, S, G) \$\endgroup\$ Commented Apr 10, 2018 at 5:55
  • \$\begingroup\$ @ASCII-only Oh nice, thanks! :) As for leaving out the sub, I don't think so. It's not a function without it. \$\endgroup\$ Commented Apr 10, 2018 at 5:59
  • \$\begingroup\$ @ASCII-only I'd consider answers without sub invalid since the result isn't something you can call or assign to a variable \$\endgroup\$ Commented Apr 10, 2018 at 5:59
4
\$\begingroup\$

PHP, 34 bytes

function(...$a){return count($a);}
\$\endgroup\$
4
  • \$\begingroup\$ Nice one! The alternative, for PHP 5.6 and older, is function(){return func_num_args();} (35 bytes, posted below). \$\endgroup\$ Commented Apr 10, 2018 at 14:16
  • \$\begingroup\$ @IsmaelMiguel This one also works in PHP 5.6. \$\endgroup\$ Commented Apr 10, 2018 at 14:56
  • 1
    \$\begingroup\$ You should mention this works only in PHP 5.6 and newer. \$\endgroup\$ Commented Apr 10, 2018 at 14:57
  • \$\begingroup\$ @axiac You're right, my bad. Was thinking about PHP5.5 \$\endgroup\$ Commented Apr 10, 2018 at 15:12
4
\$\begingroup\$

C# .NET, 11 bytes

a=>a.Length

Try it online.

Explanation:

In C# .NET object is used for multi-type arguments, allowing one to pass integers, strings, characters, etc. as possible inputs. For example:

// Can be called like: `F(2)`, `F("test")`, `F('a')`, etc.
void F(object arg){ ... }

C# .NET can also have a fixed size of optional arguments. For example:

// Can be called like: `F()`, `F(2)`, `F("test")`, `F('a')`, etc.
void F(object arg = null){ ... }

And there are also varargs, which is an undefined amount of optional arguments (which is what I've used in this answer). For example:

// Can be called like: `F()`, `F(2)`, `F(2, "test", 'a')`, etc.
void F(params object[] args){ ... }

Usually lambdas are created like this:

System.Func<object[], int> F f = a=>a.Length;
// A call like `f(new object[]{2, "test", 'a'))` will return 3 (size of the input array)

But unfortunately System.Func doesn't support params varargs, so I'll have to create a delegate instead:

delegate int F(params object[] args);
F f = a=>a.Length;
// A call like `f()` will return 0, and `f(2, "test", 'a')` will return 3

Which is my answer for this challenge, and can be found in the linked TIO test code.


The only limitation is that inputting an actual object[] like f(new object[]{1,2,3}) will result in 3 instead of 1. f(new int[]{1,2,3}) will still result in 1, because it interprets the int[] as a single object. To have the object[] parameter be interpret as a single object as well it can be casted to an object like this: f((object)new object[]{1,2,3}).

answered Apr 10, 2018 at 12:33
\$\endgroup\$
8
  • 1
    \$\begingroup\$ I have to say, if there were ever an answer that made me support including lambda-related boilerplate in C# answers it would be this one... but it is definitely a valid solution. \$\endgroup\$ Commented Apr 10, 2018 at 15:23
  • \$\begingroup\$ @KamilDrakari Maybe it indeed wasn't very clear what I did without opening the TIO-link, so I've added an explanation. \$\endgroup\$ Commented Apr 11, 2018 at 9:25
  • 1
    \$\begingroup\$ @Taemyr I tried finding a solution, but unfortunately there is none for C# .NET, except for casting any object[] parameters to object, like this: f((object)new object[]{1,2,3});. There is no way to differentiate between f(new object[]{1,2,3}); and f(1,2,3); as far as I could find. \$\endgroup\$ Commented Apr 11, 2018 at 14:58
  • 1
    \$\begingroup\$ this handles array parameters correctly for a huge penalty of bytes. There might be a more concise structure that can handle it, but it works in my testing. \$\endgroup\$ Commented Apr 11, 2018 at 15:10
  • 1
    \$\begingroup\$ @KamilDrakari Hmm, but it fails for f(1, new object[]{1,2,3}) again though. Not sure if a solution for this behavior can be found. \$\endgroup\$ Commented Apr 11, 2018 at 15:43
4
\$\begingroup\$

Dodos, (削除) 32 (削除ここまで) 31 bytes

f
	dot i f dab
i
	
	dip dot dab

Try it online!

Uses Dennis' increment function.

Explanation

f # definition of f - target function
 dot i f dab # sum of j(f(all args but first)). recurses until it has 0 args
i # definition of i - returns (arg, 1) given 1 arg
 # arg
 dip dot dab # 1 (dot dab on list of length 1 returns 0, dip returns |0 - 1|)

Alternatively, 32 bytes without recursion in target function (thanks @Leo)

	dot i
i
	dip dot dab dot
	i dab

Try it online!

Explanation

 dot i # anonymous function: sum of i(args)
 # here this becomes implicit main
i # definition of i - returns a list with all arguments replaced with 1
 dip dot dab dot # 1 (dab dot returns empty list, dot returns 0, dip returns |0 - 1|
 i dab # list concatenated with i(all args but first)
answered Apr 10, 2018 at 4:28
\$\endgroup\$
8
  • \$\begingroup\$ Here's another same-length solution Try it online! I can't seem to understand why yours works though, could you add an explanation please? \$\endgroup\$ Commented Apr 10, 2018 at 4:47
  • \$\begingroup\$ Hey, you added an explanation to my solution! I wanted one for yours, I know how mine works xD \$\endgroup\$ Commented Apr 10, 2018 at 5:34
  • 1
    \$\begingroup\$ @Leo sorry for late reply, idek what I'm doing, just copied Dennis' function, will try to understand asap. I had no idea how dodos works so I figured out what yours did first \$\endgroup\$ Commented Apr 10, 2018 at 5:36
  • \$\begingroup\$ No worries, it was just a funny situation :) \$\endgroup\$ Commented Apr 10, 2018 at 5:38
  • \$\begingroup\$ @Leo ok so does my explanation make sense? (note: I'm on mobile so feel free to edit it to make it better lol) \$\endgroup\$ Commented Apr 10, 2018 at 5:46
3
\$\begingroup\$

Rust, 57 bytes

macro_rules!f{()=>{0};($($x:expr),+)=>{[$($x),+].len()};}

Explanation:

macro_rules! f { // define a macro called f
 () => {0}; // when called without arguments, expand to 0
 ($($x:expr),+) => { // when called with 1 or more comma seperated arguments
 [ // rust uses [a, b, c] to make an array
 $($x),+ // expand to the arguments seperated with a comma
 ] 
 .len() // take the length of that.
 };
}

Test:

fn main() {
 println!("{:?}", f!()); // prints 0
 println!("{:?}", f!(4)); // prints 1
 println!("{:?}", f!(5, 2)); // prints 2
 // works with anything, as long as you dont mix things
 println!("{}", f!("", "a", "hello")); // prints 3
}
answered Apr 10, 2018 at 7:25
\$\endgroup\$
3
\$\begingroup\$

R, 20 bytes

function(...)nargs()

Try it online!

R has a function just for that.

answered Jun 8, 2018 at 14:21
\$\endgroup\$
2
\$\begingroup\$

PHP, 35 bytes

function(){return func_num_args();}

manual entry

answered Apr 10, 2018 at 3:11
\$\endgroup\$
2
\$\begingroup\$

Common Lisp, 28 bytes

(defun f(&rest a)(length a))

Try it online!

answered Apr 10, 2018 at 4:48
\$\endgroup\$
2
\$\begingroup\$

Add++, 3 bytes

L,L

Try it online!

answered Apr 10, 2018 at 7:37
\$\endgroup\$
2
\$\begingroup\$

PHP, 11 bytes

<?=$argc-1;

Try it online: 1 input | 3 inputs

answered Apr 10, 2018 at 11:32
\$\endgroup\$
6
  • \$\begingroup\$ I'm not so sure about this one (and it's validity) since it is the count of arguments passed to call PHP. \$\endgroup\$ Commented Apr 10, 2018 at 14:20
  • \$\begingroup\$ @IsmaelMiguel, see this consensus. \$\endgroup\$ Commented Apr 10, 2018 at 14:31
  • 1
    \$\begingroup\$ The question explicitly requires a function that returns the number, does not display it: "...write a function that takes a variable number of arguments and returns the number of arguments." \$\endgroup\$ Commented Apr 10, 2018 at 14:59
  • 1
    \$\begingroup\$ Re-quoting the question: "Using your language of choice, write a function that takes a variable number of arguments and returns the number of arguments it was called with.". Your code doesn't contain functions. \$\endgroup\$ Commented Apr 10, 2018 at 15:11
  • \$\begingroup\$ @IsmaelMiguel, if that were indeed the case then many other solutions would also be invalidated. The norm is to allow solutions to be programmes or functions. \$\endgroup\$ Commented Apr 11, 2018 at 9:01
2
\$\begingroup\$

PowerShell 3, 25 bytes

function a(){$args.Count}

Usage:

a 1 2 ...

Console output for "a 1 2 3"

PS: C:\> a 1 2 3
3

Pretty self explanatory. Powershell stores all unspecified args in the $args list, so we just grab a count of it. Since the language implicitly writes values to the console, the act of finding the count will print to the console without needing a Write-Host or Write-Output.

Edit: Mistyped; should have been 25 bytes (typed 35).

answered Apr 10, 2018 at 15:12
\$\endgroup\$
2
  • 1
    \$\begingroup\$ You can use filter instead of function. Or just raw scriptblock: .{$args.Count} 1 2 3 4 5 \$\endgroup\$ Commented Apr 10, 2018 at 18:56
  • \$\begingroup\$ Good idea. I chose "function" to fulfill the challenge text: Using your language of choice, write a function that takes a variable number of arguments... I guess it depends on how loose the definition of "function" is in this case. \$\endgroup\$ Commented Apr 10, 2018 at 20:26
2
\$\begingroup\$

Batch, (削除) 50 (削除ここまで) 49 bytes

set n=0
for %%a in (%*)do set/an+=1
exit/b%n%

No builtin in Batch, so we have to go old-school. Saved 1 byte thanks to @IsmaelMiguel. Outputs via exit code, or save 3 bytes if output via global variable is valid. Example of use in a full program:

@echo off
call:c %*
echo %ERRORLEVEL%
exit/b
:c
set n=0
for %%a in (%*)do set/an+=1
exit/b%n%
answered Apr 10, 2018 at 8:16
\$\endgroup\$
3
  • \$\begingroup\$ I believe that this answer is answer goes (somewhat) against the rules. Batch has something somewhat close to functions. You can do something similar to :a|set r=0&for %%a in (%*)do set/ar+=1 (| = windows-style newline). This solution is 38 bytes. To execute it, do call :a <args> with a goto :eof before the function, being the value available inside the variable r. If you want to keep your solution, remove the /a on the first set, and remove those @. \$\endgroup\$ Commented Apr 11, 2018 at 9:39
  • \$\begingroup\$ @IsmaelMiguel Like this? (Note: I didn't include the function name in the byte count, but I did include the function return, which seems reasonable, as there needs to be one somewhere.) \$\endgroup\$ Commented Apr 11, 2018 at 11:32
  • \$\begingroup\$ Yes, that's exactly it. Nice catch with the exit code! I was surprised to see that exitcodes can be larger than 255. An example is the list provided by Symantec: symantec.com/connect/articles/… \$\endgroup\$ Commented Apr 11, 2018 at 12:36
2
\$\begingroup\$

x86 32-bit (i386) machine code function, 13 bytes

Calling convention: i386 System V (stack args), with a NULL pointer as a sentinel / terminator for the end-of-arg-list. (Clobbers EDI, otherwise complies with SysV).

C (and asm) don't pass type info to variadic functions, so the OP's description of passing integers or arrays with no explicit type info could only be implemented in a convention that passed some kind of struct / class object (or pointers to such), not bare integers on the stack. So I decided to assume that all the args were non-NULL pointers, and the caller passes a NULL terminator.

A NULL-terminated pointer list of args is actually used in C for functions like POSIX execl(3) : int execl(const char *path, const char *arg, ... /* (char *) NULL */);

C doesn't allow int foo(...); prototypes with no fixed arg, but int foo(); means the same thing: args unspecified. (Unlike in C++ where it means int foo(void)). In any case, this is an asm answer. Coaxing a C compiler to call this function directly is interesting but not required.

nasm -felf32 -l/dev/stdout arg-count.asm with some comment lines removed.

24 global argcount_pointer_loop
25 argcount_pointer_loop:
26 .entry:
28 00000000 31C0 xor eax, eax ; search pattern = NULL
29 00000002 99 cdq ; counter = 0
30 00000003 89E7 mov edi, esp
31 ; scasd ; edi+=4; skip retaddr
32 .scan_args:
33 00000005 42 inc edx
34 00000006 AF scasd ; cmp eax,[edi] / edi+=4
35 00000007 75FC jne .scan_args
36 ; dec edx ; correct for overshoot: don't count terminator
37 ; xchg eax,edx
38 00000009 8D42FE lea eax, [edx-2] ; terminator + ret addr
40 0000000C C3 ret
size = 0D db $ - .entry

The question shows that the function must be able to return 0, and I decided to follow that requirement by not including the terminating NULL pointer in the arg count. This does cost 1 byte, though. (For the 12-byte version, remove the LEA and uncomment the scasd outside the loop and the xchg, but not the dec edx. I used LEA because it costs the same as those other three instructions put together, but is more efficient, so the function is fewer uops.)

C caller for testing:

Built with:

nasm -felf32 -l /dev/stdout arg-count.asm | cut -b -28,$((28+12))- &&
 gcc -Wall -O3 -g -std=gnu11 -m32 -fcall-used-edi arg-count.c arg-count.o -o ac &&
 ./ac

-fcall-used-edi is required even at -O0 to tell gcc to assume that functions clobber edi without saving/restoring it, because I used so many calls in one C statement (the printf call) that even -O0 was using EDI. It appears to be safe for gcc's main to clobber EDI from its own caller (in CRT code), on Linux with glibc, but otherwise it's totally bogus to mix/match code compiled with different -fcall-used-reg. There's no __attribute__ version of it to let us declare the asm functions with custom calling conventions different from the usual.

#include <stdio.h>
int argcount_rep_scas(); // not (...): ISO C requires at least one fixed arg
int argcount_pointer_loop(); // if you declare args at all
int argcount_loopne();
#define TEST(...) printf("count=%d = %d = %d (scasd/jne) | (rep scas) | (scas/loopne)\n", \
 argcount_pointer_loop(__VA_ARGS__), argcount_rep_scas(__VA_ARGS__), \
 argcount_loopne(__VA_ARGS__))
int main(void) {
 TEST("abc", 0);
 TEST(1, 1, 1, 1, 1, 1, 1, 0);
 TEST(0);
}

Two other versions also came in at 13 bytes: this one based on loopne returns a value that's too high by 1.

45 global argcount_loopne
46 argcount_loopne:
47 .entry:
49 00000010 31C0 xor eax, eax ; search pattern = NULL
50 00000012 31C9 xor ecx, ecx ; counter = 0
51 00000014 89E7 mov edi, esp
52 00000016 AF scasd ; edi+=4; skip retaddr
53 .scan_args:
54 00000017 AF scasd
55 00000018 E0FD loopne .scan_args
56 0000001A 29C8 sub eax, ecx
58 0000001C C3 ret
size = 0D = 13 bytes db $ - .entry

This version uses rep scasd instead of a loop, but takes the arg count modulo 256. (Or capped at 256 if the upper bytes of ecx are 0 on entry!)

63 ; return int8_t maybe?
64 global argcount_rep_scas
65 argcount_rep_scas:
66 .entry:
67 00000020 31C0 xor eax, eax
68 ; lea ecx, [eax-1]
69 00000022 B1FF mov cl, -1
70 00000024 89E7 mov edi, esp
71 ; scasd ; skip retaddr
72 00000026 F2AF repne scasd ; ecx = -len - 2 (including retaddr)
73 00000028 B0FD mov al, -3
74 0000002A 28C8 sub al, cl ; eax = -3 +len + 2
75 ; dec eax
76 ; dec eax
77 0000002C C3 ret
size = 0D = 13 bytes db $ - .entry

Amusingly, yet another version based on inc eax / pop edx / test edx,edx / jnz came in at 13 bytes. It's a callee-pops convention, which is never used by C implementations for variadic functions. (I popped the ret addr into ecx, and jmp ecx instead of ret. (Or push/ret to not break the return-address predictor stack).

answered Apr 13, 2018 at 10:06
\$\endgroup\$
2
\$\begingroup\$

Go, (削除) 44 (削除ここまで) (削除) 30 (削除ここまで) 28 bytes

-2 bytes thanks to BMO

My first code golf attempt.

func(a...int){print(len(a))}

Try it online (outputs to Debug-window instead of STDOUT).

answered Apr 10, 2018 at 12:10
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Welcome to the site! I've edited your post to match the general answer format we use here. Is it possible for you to edit in a link to somewhere where others can test your code, such as Try It Online! \$\endgroup\$ Commented Apr 10, 2018 at 12:15
  • \$\begingroup\$ added a link to a modified workign example, sadly go only runs main packages \$\endgroup\$ Commented Apr 10, 2018 at 12:26
  • \$\begingroup\$ Welcome to PPCG! I noticed you had your TIO-link in your header. So I've put it below it, and fixed the header-link. Enjoy your stay! \$\endgroup\$ Commented Apr 10, 2018 at 13:49
1
2 3

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.