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
intis still valid), arbitrary types (any type of argument is allowed), or any combination of argument types (e.g. first arg isint, 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()returns0f(1)orf("a")returns1f([1, 2, 3])returns1as it is passed an array, not 3 argumentsf(1, 10)orf(1, "a")returns2
As this is code-golf, the winning solution is the one that uses the fewest number of bytes.
-
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\$user202729– user2027292018年04月10日 05:06:28 +00:00Commented 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\$Sanchises– Sanchises2018年04月10日 07:46:26 +00:00Commented 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\$Sanchises– Sanchises2018年04月10日 13:58:53 +00:00Commented 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\$Conor O'Brien– Conor O'Brien2018年04月11日 02:06:50 +00:00Commented 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\$Glenn Smith– Glenn Smith2018年04月11日 08:23:40 +00:00Commented Apr 11, 2018 at 8:23
81 Answers 81
-
33\$\begingroup\$ Java beating Javscript is rare enouth to be noticed \$\endgroup\$The random guy– The random guy2018年04月10日 07:08:52 +00:00Commented 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\$SamYonnou– SamYonnou2018年04月10日 15:40:56 +00:00Commented Apr 10, 2018 at 15:40 -
5\$\begingroup\$ @SamYonnou There is no difference with other lambdas, and as you mentioned, lambdas are fine. \$\endgroup\$Olivier Grégoire– Olivier Grégoire2018年04月10日 16:15:12 +00:00Commented 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\$SamYonnou– SamYonnou2018年04月11日 18:09:45 +00:00Commented Apr 11, 2018 at 18:09
-
1\$\begingroup\$ @PeterCordes That's why the "Try it online" link in my answer exists ;-) \$\endgroup\$Olivier Grégoire– Olivier Grégoire2018年04月12日 22:43:27 +00:00Commented Apr 12, 2018 at 22:43
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
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))
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
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.
-
\$\begingroup\$ Damn, you beat me to it.
fis optional if you sayz 0is the function without the binding, somain = print $ ((z 0) pi 0 () [] :: Int)works. \$\endgroup\$Angs– Angs2018年04月10日 07:40:55 +00:00Commented 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\$Angs– Angs2018年04月10日 07:55:20 +00:00Commented 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\$user79465– user794652018年04月10日 08:07:14 +00:00Commented Apr 10, 2018 at 8:07
-
\$\begingroup\$ I guess the
::Intshould be counted in the byte count, since the type of the answer has to be declared sooner or later, like inmain = 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 likefoldl(\a b->a b) (z 0) $ [1..5])::Intcan't work. Either way, this is great stuff. \$\endgroup\$Angs– Angs2018年04月10日 11:04:21 +00:00Commented Apr 10, 2018 at 11:04 -
2\$\begingroup\$
s/imperative/non-curry/\$\endgroup\$user202729– user2027292018年04月10日 15:51:46 +00:00Commented Apr 10, 2018 at 15:51
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)Acontains 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 to0, except the two undefined flags which are both1. TheZflag (zero) is SET to1if there were no parameters passed in
BCB- 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 inHL- 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 parameterIY-&0000
The code
LoaDs the address pointed to byDEwith the value inAINCrementsDEXORsA(withA), giving&00LoaDs the value inAto the address pointed to byDERETurns
On exit:
Ais destroyed (it's always&00)DEis 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%- INTEGERx$- 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 aDEFINT 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.
-
\$\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\$Peter Cordes– Peter Cordes2018年04月12日 16:03:03 +00:00Commented 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
Ais the same immediately after theRETinstruction. The lifespan of a value inAis very short since it's the accumulator. There's no such thing asx = CALL &8000, 42. It would have to beCALL &8000, x, 42, and extra Z80 code, but thenxwould be2, not1. \$\endgroup\$CJ Dennis– CJ Dennis2018年04月12日 22:26:36 +00:00Commented 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\$Peter Cordes– Peter Cordes2018年04月12日 22:32:12 +00:00Commented 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 -NOPno-ops. Another byte can be added to make it safer, but of course without a return parameter it can't set anything. \$\endgroup\$CJ Dennis– CJ Dennis2018年04月13日 13:44:44 +00:00Commented Apr 13, 2018 at 13:44
-
6\$\begingroup\$ Also, Python 2 :) \$\endgroup\$Chas Brown– Chas Brown2018年04月10日 03:09:48 +00:00Commented Apr 10, 2018 at 3:09
-
\$\begingroup\$ It's not at all surprising that this was the first answer. ;) \$\endgroup\$jpmc26– jpmc262018年04月14日 03:38:22 +00:00Commented Apr 14, 2018 at 3:38
-
\$\begingroup\$ Though it should probably be wrapped:
f(){ echo $#; }\$\endgroup\$muru– muru2018年04月10日 07:39:23 +00:00Commented Apr 10, 2018 at 7:39 -
8\$\begingroup\$ @muru That looks fine as a full program to me. \$\endgroup\$Neil– Neil2018年04月10日 08:14:31 +00:00Commented Apr 10, 2018 at 8:14
-
\$\begingroup\$ Although, I see now that the OP only wants a function... \$\endgroup\$Neil– Neil2018年04月10日 15:50:15 +00:00Commented 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\$Pavel– Pavel2018年04月10日 17:28:51 +00:00Commented Apr 10, 2018 at 17:28
Brain-Flak, 6 bytes
My first Brain-Flak solution worthy posting, I guess it's the right tool for this job:
([]<>)
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
Wolfram Language (Mathematica), 11 bytes
Tr[1^{##}]&
Suggested by JungHwan Min. Some restrictions (input must be rectangular) but we are not required to handle arbitrary input.
11 bytes
Length@!##&
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@{##}&
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.
-
1\$\begingroup\$
function(...)nargs()is 20 bytes, but usinglength(...)was my initial approach until I googled anargs-like function. \$\endgroup\$Giuseppe– Giuseppe2018年04月10日 12:15:11 +00:00Commented Apr 10, 2018 at 12:15 -
\$\begingroup\$ @Giuseppe hmm, I tried converting the
list(...)to a logical sosum()could be used, but that's tricky :/ \$\endgroup\$JAD– JAD2018年04月10日 12:23:32 +00:00Commented Apr 10, 2018 at 12:23 -
1\$\begingroup\$ Haha, don't try and bait me into that argument ;) \$\endgroup\$RoryT– RoryT2018年04月11日 08:43:59 +00:00Commented Apr 11, 2018 at 8:43
-
1\$\begingroup\$ @RoryT oh actually, R docs say combine. Nevermind :D \$\endgroup\$JAD– JAD2018年04月11日 08:44:40 +00:00Commented Apr 11, 2018 at 8:44
-
2\$\begingroup\$
...length()does the same thing aslength(list(...))\$\endgroup\$Giuseppe– Giuseppe2018年04月17日 16:42:19 +00:00Commented Apr 17, 2018 at 16:42
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
-
2\$\begingroup\$ Welcome to PPCG! \$\endgroup\$Martin Ender– Martin Ender2018年04月10日 18:52:16 +00:00Commented 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 ... argnit will be interpreted by bash.) \$\endgroup\$Olivier Dulac– Olivier Dulac2018年04月13日 13:04:50 +00:00Commented Apr 13, 2018 at 13:04 -
\$\begingroup\$ @Olivier Dulac The challenge clearly says a function. \$\endgroup\$Wastrel– Wastrel2018年04月13日 17:04:03 +00:00Commented Apr 13, 2018 at 17:04
C++14 (gcc), 34 bytes
As generic variadic lambda function (C++14 required):
[](auto...p){return sizeof...(p);}
Previous (incorrect) answer: 32 bytes
It was missing the template<class...T> and (p)
int f(T...p){return sizeof...p;}
-
7\$\begingroup\$ C++14, C++11 has no generic lambdas. \$\endgroup\$Quentin– Quentin2018年04月10日 12:55:54 +00:00Commented Apr 10, 2018 at 12:55
-
1\$\begingroup\$ You could add the permissive flag to be able to remove the parenthesis around
p(and-wto turn off the warning). \$\endgroup\$nwp– nwp2018年04月10日 16:00:37 +00:00Commented Apr 10, 2018 at 16:00 -
\$\begingroup\$ @nwp: wouldn't
-fpermissivecost you the 12 bytes for that option, though? If it's not standard ISO C++ or GNU C++. \$\endgroup\$Peter Cordes– Peter Cordes2018年04月12日 16:05:17 +00:00Commented 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\$nwp– nwp2018年04月12日 16:16:00 +00:00Commented Apr 12, 2018 at 16:16
-
\$\begingroup\$ @Quentin fixed -> C++14 \$\endgroup\$Bierpfurz– Bierpfurz2018年04月15日 07:15:46 +00:00Commented Apr 15, 2018 at 7:15
Octave, 9 bytes
@()nargin
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.
Ruby, 12 bytes
->*a{a.size}
*a is a splat of the arguments, making a consume all arguments passed to the Proc. a.size obtains its size.
-
\$\begingroup\$ You could just do
{+@_}\$\endgroup\$elcaro– elcaro2018年04月10日 04:44:41 +00:00Commented Apr 10, 2018 at 4:44 -
\$\begingroup\$ @Joshua >_> true, thanks \$\endgroup\$ASCII-only– ASCII-only2018年04月10日 04:48:03 +00:00Commented Apr 10, 2018 at 4:48
-
\$\begingroup\$ You can remove the
subin Perl 6 (not in Perl 5, though). \$\endgroup\$nwellnhof– nwellnhof2018年04月10日 17:47:43 +00:00Commented Apr 10, 2018 at 17:47 -
\$\begingroup\$ @nwellnhof Oh, TIL. Perl 6 is so different from Perl 5 >_> \$\endgroup\$ASCII-only– ASCII-only2018年04月11日 00:44:42 +00:00Commented Apr 11, 2018 at 0:44
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.
-
\$\begingroup\$ You can use
sizeof.... \$\endgroup\$L. F.– L. F.2019年07月23日 04:02:54 +00:00Commented Jul 23, 2019 at 4:02
-
\$\begingroup\$ A quick sitewide search of answers seems to indicate that you can leave out the
sub\$\endgroup\$ASCII-only– ASCII-only2018年04月10日 05:53:58 +00:00Commented Apr 10, 2018 at 5:53 -
2\$\begingroup\$ Protip: TIO let's you copy in PPCG post format (ESC, S, G) \$\endgroup\$ASCII-only– ASCII-only2018年04月10日 05:55:03 +00:00Commented 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\$Chris– Chris2018年04月10日 05:59:26 +00:00Commented Apr 10, 2018 at 5:59 -
\$\begingroup\$ @ASCII-only I'd consider answers without
subinvalid since the result isn't something you can call or assign to a variable \$\endgroup\$Ton Hospel– Ton Hospel2018年04月10日 05:59:46 +00:00Commented Apr 10, 2018 at 5:59
PHP, 34 bytes
function(...$a){return count($a);}
-
\$\begingroup\$ Nice one! The alternative, for PHP 5.6 and older, is
function(){return func_num_args();}(35 bytes, posted below). \$\endgroup\$Ismael Miguel– Ismael Miguel2018年04月10日 14:16:57 +00:00Commented Apr 10, 2018 at 14:16 -
\$\begingroup\$ @IsmaelMiguel This one also works in PHP 5.6. \$\endgroup\$axiac– axiac2018年04月10日 14:56:33 +00:00Commented Apr 10, 2018 at 14:56
-
1\$\begingroup\$ You should mention this works only in PHP 5.6 and newer. \$\endgroup\$axiac– axiac2018年04月10日 14:57:03 +00:00Commented Apr 10, 2018 at 14:57
-
\$\begingroup\$ @axiac You're right, my bad. Was thinking about PHP5.5 \$\endgroup\$Ismael Miguel– Ismael Miguel2018年04月10日 15:12:32 +00:00Commented Apr 10, 2018 at 15:12
C# .NET, 11 bytes
a=>a.Length
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}).
-
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\$Kamil Drakari– Kamil Drakari2018年04月10日 15:23:43 +00:00Commented 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\$Kevin Cruijssen– Kevin Cruijssen2018年04月11日 09:25:05 +00:00Commented 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 toobject, like this:f((object)new object[]{1,2,3});. There is no way to differentiate betweenf(new object[]{1,2,3});andf(1,2,3);as far as I could find. \$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2018年04月11日 14:58:16 +00:00Commented 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\$Kamil Drakari– Kamil Drakari2018年04月11日 15:10:45 +00:00Commented 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\$Kevin Cruijssen– Kevin Cruijssen2018年04月11日 15:43:14 +00:00Commented Apr 11, 2018 at 15:43
Dodos, (削除) 32 (削除ここまで) 31 bytes
f
dot i f dab
i
dip dot dab
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
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)
-
\$\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\$Leo– Leo2018年04月10日 04:47:49 +00:00Commented 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\$Leo– Leo2018年04月10日 05:34:37 +00:00Commented 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\$ASCII-only– ASCII-only2018年04月10日 05:36:21 +00:00Commented Apr 10, 2018 at 5:36
-
\$\begingroup\$ No worries, it was just a funny situation :) \$\endgroup\$Leo– Leo2018年04月10日 05:38:13 +00:00Commented 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\$ASCII-only– ASCII-only2018年04月10日 05:46:53 +00:00Commented Apr 10, 2018 at 5:46
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
}
-
\$\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\$Ismael Miguel– Ismael Miguel2018年04月10日 14:20:09 +00:00Commented Apr 10, 2018 at 14:20
-
\$\begingroup\$ @IsmaelMiguel, see this consensus. \$\endgroup\$Shaggy– Shaggy2018年04月10日 14:31:08 +00:00Commented 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\$axiac– axiac2018年04月10日 14:59:20 +00:00Commented 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\$Ismael Miguel– Ismael Miguel2018年04月10日 15:11:28 +00:00Commented 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\$Shaggy– Shaggy2018年04月11日 09:01:47 +00:00Commented Apr 11, 2018 at 9:01
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).
-
1\$\begingroup\$ You can use
filterinstead offunction. Or just raw scriptblock:.{$args.Count} 1 2 3 4 5\$\endgroup\$beatcracker– beatcracker2018年04月10日 18:56:06 +00:00Commented 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\$Arkitekt– Arkitekt2018年04月10日 20:26:28 +00:00Commented Apr 10, 2018 at 20:26
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%
-
\$\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, docall :a <args>with agoto :eofbefore the function, being the value available inside the variabler. If you want to keep your solution, remove the/aon the firstset, and remove those@. \$\endgroup\$Ismael Miguel– Ismael Miguel2018年04月11日 09:39:56 +00:00Commented 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\$Neil– Neil2018年04月11日 11:32:06 +00:00Commented 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\$Ismael Miguel– Ismael Miguel2018年04月11日 12:36:20 +00:00Commented Apr 11, 2018 at 12:36
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).
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).
-
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\$2018年04月10日 12:15:46 +00:00Commented Apr 10, 2018 at 12:15
-
\$\begingroup\$ added a link to a modified workign example, sadly go only runs main packages \$\endgroup\$Pizza lord– Pizza lord2018年04月10日 12:26:21 +00:00Commented 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\$Kevin Cruijssen– Kevin Cruijssen2018年04月10日 13:49:27 +00:00Commented Apr 10, 2018 at 13:49