I am building an API where I allow the users to passes 2 different list of custom fields.
The API is basically this:
def action(type, name, date, name_custom_1, name_custom_2, name_custom_3, date_custom_1, date_custom_2, date_custom_3, date_custom_4)
So type, name date are parameter of this API and are mandatory.
name_custom_*, and date_custom_* are optionals, I could have 0, 1, 2, 3 ...
I am putting a limit to 3 for name_custom and 4 to date_cutom for technical reasons, but eventually this limit can get increased (but never extremely will never be completely remove)
Now my question is, what is the best way to make this API, from a user point of view:
def action(type, name, date, name_custom_1, name_custom_2, name_custom_3, date_custom_1, date_custom_2, date_custom_3, date_custom_4)
or
def action(type, name, date, names_custom, dates_custom):
Where names_custom and dates_custom are a list which can not be bigger than X.
I am struggling between both and find value and logic in both. Any suggestions?
The list parameters give a cleaner solution, because:
There are less arguments in the function signature, making the documentation easier to read for humans.
It is more resilient to change. Suppose you decide to change the maximum number of custom arguments from 4 to 5. In the list approach, the change is simpler.
Even having 5 arguments in a function call is more than usual, and often considered sloppy (see How many parameters are too many?). You may want to consider introducing a class, or a few classes in here. Depending on your application, maybe it makes sense to create class that encapsulates the name and the list of custom names, and a class that encapsulates the date and the list of custom dates? And perhaps the action itself is better off being a class with a number of setter methods?
In other words, if your functions become long, or argument lists become long, it is often a sign that there are classes waiting to be discovered underneath your design.
Related
This code works:
(3,6...66).contains( 9|21 ).say # OUTPUT: «any(True, True)»
And returns a Junction. It's also tested, but not documented.
The problem is I can't find its implementation anywhere. The Str code, which is also called from Cool, never returns a Junction (it does not take a Junction, either). There are no other methods contain in source.
Since it's autothreaded, it's probably specially defined somewhere. I have no idea where, though. Any help?
TL;DR Junction autothreading is handled by a single central mechanism. I have a go at explaining it below.
(The body of your question starts with you falling into a trap, one I think you documented a year or two back. It seems pretty irrelevant to what you're really asking but I cover that too.)
How junctions get handled
Where is contains( Junction) defined? ... The problem is I can't find [the Junctional] implementation anywhere. ... Since it's autothreaded, it's probably specially defined somewhere.
Yes. There's a generic mechanism that automatically applies autothreading to all P6 routines (methods, operators etc.) that don't have signatures that explicitly control what happens with Junction arguments.
Only a tiny handful of built in routines have these explicit Junction handling signatures -- print is perhaps the most notable. The same is true of user defined routines.
.contains does not have any special handling. So it is handled automatically by the generic mechanism.
Perhaps the section The magic of Junctions of my answer to an earlier SO Filtering elements matching two regexes will be helpful as a high level description of the low level details that follow below. Just substitute your 9|21 for the foo & bar in that SO, and your .contains for the grep, and it hopefully makes sense.
Spelunking the code
I'll focus on methods. Other routines are handled in a similar fashion.
method AUTOTHREAD does the work for full P6 methods.
This is setup in this code that sets up handling for both nqp and full P6 code.
The above linked P6 setup code in turn calls setup_junction_fallback.
When a method call occurs in a user's program, it involves calling find_method (modulo cache hits as explained in the comment above that code; note that the use of the word "fallback" in that comment is about a cache miss -- which is technically unrelated to the other fallback mechanisms evident in this code we're spelunking thru).
The bit of code near the end of this find_method handles (non-cache-miss) fallbacks.
Which arrives at find_method_fallback which starts off with the actual junction handling stuff.
A trap
This code works:
(3,6...66).contains( 9|21 ).say # OUTPUT: «any(True, True)»
It "works" to the degree this does too:
(3,6...66).contains( 2 | '9 1' ).say # OUTPUT: «any(True, True)»
See Lists become strings, so beware .contains() and/or discussion of the underlying issues such as pmichaud's comment.
Routines like print, put, infix ~, and .contains are string routines. That means they coerce their arguments to Str. By default the .Str coercion of a listy value is its elements separated by spaces:
put 3,6...18; # 3 6 9 12 15 18
put (3,6...18).contains: '9 1'; # True
It's also tested
Presumably you mean the two tests with a *.contains argument passed to classify:
my $m := #l.classify: *.contains: any 'a'..'f';
my $s := classify *.contains( any 'a'..'f'), #l;
Routines like classify are list routines. While some list routines do a single operation on their list argument/invocant, eg push, most of them, including classify, iterate over their list doing something with/to each element within the list.
Given a sequence invocant/argument, classify will iterate it and pass each element to the test, in this case a *.contains.
The latter will then coerce individual elements to Str. This is a fundamental difference compared to your example which coerces a sequence to Str in one go.
If a REST API endpoint gets all, then filters are easy. Lack of a filter means "get all results".
GET /persons - gets all persons
GET /persons?name=john - gets all persons with name of "john"
But if there is a default, then I need some way to explicitly not set the default filter. Continuing the above example, if each person has a state, "approved" or "pending", and if my system is set such that if I do not explicitly specify a state, it will return all "approved":
GET /persons - gets all approved persons, because defaults to state=approved
GET /persons?state=approved - same thing, gets all approved persons
GET /persons?state=pending - gets all pending persons
How do I get all persons? What if there are 10 possible states? Or 100?
I can think of a few ways:
GET /persons?state=any - but then I can never use the actual state any
GET /persons?state=* - would work, but feels strange? Or is it?
GET /persons?state= - some URL parsing libraries would complain about a blank query parameter, and does this not imply "state is empty" as opposed to "state is anything"?
How do I say in my GET, "override the default for the state to be anything"?
Maybe this could work for you:
GET /persons?state - gets all persons that have a state name, no matter which value
GET /persons?state= - gets all persons that have an empty value for the state name
You probably don’t need to differentiate between these two situations, so you could use either one for getting all persons with the state name (I just think that the variant without = is more beautiful).
FWIW, the application/x-www-form-urlencoded format (i.e., typically used in HTML forms) doesn’t differ between an empty and no value.
As far as the URI standard is concerned, this name-value pair syntax in the query component is only a convention anyway, so you can use whichever syntax/semantics you wish.
I don't think there is one answer to this question. As long as you document that the default state is approved well I don't think it matter to the clients if you pass any, * etc. All of your proposals are fine except the last one. I don't think that is a good one.
If I was designing the API I would use all and keep this as a standard. I would also recommend to use paging for all endpoints that returns list of elements. I use offset and limit as paging query parameters. In my API I return 20 elements as default if the client haven't specified another paging criteria.
Imagine you have a function that converts ints to roman string:
public String roman(int)
Only numbers from 1 to 3999 (inclusive) are valid for conversion.
So what do you do if someone passes 4000 in any OO language?
raise an exception
return “” or some other special string
write an assert
…
Number 1: raise an exception. That's what ArgumentOutOfRangeException is for (at least in .NET):
if (intToConvert >= 4000)
{
throw new ArgumentOutOfRangeException("intToConvert ", "Only numbers 1-3000 are valid for conversion.");
}
I find the validation topic very interesting in general. In my opinion option 2 (returning a special value) is not a good one, since you are forcing the client to do if/case to check for the returned value and that code must be repeated everywhere. Also, unlike exceptions that propagate through the calling stack, in this scenario the caller is almost always the one that has to handle that special value.
In the context of OOP raising an exception or having an assertion is, IMO, a more elegant way to cope with it. However i find that inlining verification code in every method doesn't scale well for some reasons:
Many times your validation logic ends up being greater than the method logic itself, so you end up cluttering your code with things that are not entirely relevant to it.
There is no proper validation code reuse (e.g. range validation, e-mail validation, etc).
This one depends on your tastes, but you will be doing defensive programming.
Some years ago I attended to a talk about validators (a similar talk slide's are here. The document explaining it used to be in http://www.caesarsystems.com/resources/caesarsystems/files/Extreme_Validation.pdf but now its a 404 :( ) and totally like the concept. IMHO having a validation framework that adopts the OO philosophy is the way to go. In case you want to read about it I've written a couple of posts about it here and here (disclaimer: the posts are part of the blog of the company I work for).
HTH
Consider the case where a certain mocked function is expected to be called several times, each time with a different value in a certain parameter. I would like to validate that the function was indeed called once and only once per value in a certain list of values (e.g. 1,2,5).
On the other hand, I would like to refrain from defining a sequence as that would dictate a certain order, which is an implementation detail I would like to keep free.
Is there some kind of matcher, or other solution for this case?
I'm not sure if this influences the solution in any way but I do intend to use WillOnce(Return(x)) with a different x per value in the list above.
By default gMock expectations can be satisfied in any order (precisely for the reason you mention -- so you don't over specify your tests).
In your case, you just want something like:
EXPECT_CALL(foo, DoThis(1));
EXPECT_CALL(foo, DoThis(2));
EXPECT_CALL(foo, DoThis(5));
And something like:
foo.DoThis(5);
foo.DoThis(1);
foo.DoThis(2);
Would satisfy those expectations.
(Aside: If you did want to constrain the order, you should use InSequence: https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#expecting-ordered-calls-orderedcalls)
If you expect a function, DoThing, to be called with many different parameters, you can use the following pattern:
for (auto const param : {1, 2, 3, 7, -1, 2}){
EXPECT_CALL(foo, DoThing(param));
}
This is particularly helpful if your EXPECT_CALL includes many parameters, of which only one is changing, or if your EXPECT_CALL includes many Actions to be repeated.
In algebra if I make the statement x + y = 3, the variables I used will hold the values either 2 and 1 or 1 and 2. I know that assignment in programming is not the same thing, but I got to wondering. If I wanted to represent the value of, say, a quantumly weird particle, I would want my variable to have two values at the same time and to have it resolve into one or the other later. Or maybe I'm just dreaming?
Is it possible to say something like i = 3 or 2;?
This is one of the features planned for Perl 6 (junctions), with syntax that should look like my $a = 1|2|3;
If ever implemented, it would work intuitively, like $a==1 being true at the same time as $a==2. Also, for example, $a+1 would give you a value of 2|3|4.
This feature is actually available in Perl5 as well through Perl6::Junction and Quantum::Superpositions modules, but without the syntax sugar (through 'functions' all and any).
At least for comparison (b < any(1,2,3)) it was also available in Microsoft Cω experimental language, however it was not documented anywhere (I just tried it when I was looking at Cω and it just worked).
You can't do this with native types, but there's nothing stopping you from creating a variable object (presuming you are using an OO language) which has a range of values or even a probability density function rather than an actual value.
You will also need to define all the mathematical operators between your variables and your variables and native scalars. Same goes for the equality and assignment operators.
numpy arrays do something similar for vectors and matrices.
That's also the kind of thing you can do in Prolog. You define rules that constraint your variables and then let Prolog resolve them ...
It takes some time to get used to it, but it is wonderful for certain problems once you know how to use it ...
Damien Conways Quantum::Superpositions might do what you want,
https://metacpan.org/pod/Quantum::Superpositions
You might need your crack-pipe however.
What you're asking seems to be how to implement a Fuzzy Logic system. These have been around for some time and you can undoubtedly pick up a library for the common programming languages quite easily.
You could use a struct and handle the operations manualy. Otherwise, no a variable only has 1 value at a time.
A variable is nothing more than an address into memory. That means a variable describes exactly one place in memory (length depending on the type). So as long as we have no "quantum memory" (and we dont have it, and it doesnt look like we will have it in near future), the answer is a NO.
If you want to program and to modell this behaviour, your way would be to use a an array (with length equal to the number of max. multiple values). With this comes the increased runtime, hence the computations must be done on each of the values (e.g. x+y, must compute with 2 different values x1+y1, x2+y2, x1+y2 and x2+y1).
In Perl , you can .
If you use Scalar::Util , you can have a var take 2 values . One if it's used in string context , and another if it's used in a numerical context .