How would you define a simple "min" method in obj-c
Asked Answered
S

7

22

I want to define a min and max methods in a Utils class.

@interface Utils

int min(int a, int b);
int max(int a, int b);

@end

But I don't want to have named parameters. It would be a too heavy notation. I wanted to use the C-style definition. But then [Utils min(a, b)] as a call doesn't work. What is my problem?

Thanks in advance for any help

Spotty answered 23/1, 2010 at 23:14 Comment(4)
Hey Fred, If you want to use Object-C to do it, so use the language syntax, and if you are not happy with this, use pure C/C++, that will do what you want, in the way that you want. Cheers,Lysippus
why are there MIN and MAX macros and some platforms then?Spotty
CAUTION: The currently accepted answer is considered insecure. (see my comment/answer)Repulsive
CAUTION: "Insecure" Objective-C code may result in [self mutilate].Bespatter
D
17

Since you aren't using the OS X Implementation of objective-c, you may not have access to the predefined MIN and MAX macros.

You can define these yourself as

#define MIN(a,b)    ((a) < (b) ? (a) : (b))
#define MAX(a,b)    ((a) > (b) ? (a) : (b))

There is probably a better way to define them, but these will create the simple macros for your use. You can add them into any common .h file that your classes normally share.

Deflexed answered 23/1, 2010 at 23:51 Comment(1)
These are to be used with a grain of salt. MIN(i++, j++) for example does not result the expected. See my answer for details and solution.Repulsive
P
64

It is already defined as a macro.

MIN(a, b)

MAX(a, b)

You dont need to redefine these ones.

Pareira answered 23/1, 2010 at 23:23 Comment(4)
Was about to point this out. Why write your own when it is already implemented in the obj-c runtime.Deflexed
is it in the obj-c runtime or in the MacOS one. I'm using gcc-objective-c and I couldn't use these macros.Spotty
It is defined in NSObjCRuntime.h, which many not be in the gcc-objective-c include files.Deflexed
@FredPolack, if you are not with OS X, try C99 with the macro fmin( x, y ) in header math.h. It's a macro that calls a function, so it works well with arguments with side-effect (unlike the one provided by Brandon).Pyoid
R
30

There's a serious issue with the solution posted by Brandon Bodnár (which by the time of this writing is marked as a valid solution).

Issue described here: http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Min-and-Max.html And the (valid & secure) solution to it: http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Typeof.html

Check it out yourself:

#include <stdio.h>

#define NAIVE_MAX(a,b) (a > b ? a : b)

#define NAIVE_MIN(a,b) (a < b ? a : b)

#if !defined MAX
#define MAX(a,b) \
({ __typeof__ (a) __a = (a); \
__typeof__ (b) __b = (b); \
__a > __b ? __a : __b; })
#endif

#if !defined MIN
#define MIN(a,b) \
({ __typeof__ (a) __a = (a); \
__typeof__ (b) __b = (b); \
__a < __b ? __a : __b; })
#endif

int main (int argc, const char * argv[]) {
    int a = 3;
    int b = 5;

#pragma mark NON-FATAL CASES:
    printf("NAIVE_MAX(%d, %d) => %d\n", a, b, NAIVE_MAX(a, b));
    printf("NAIVE_MIN(%d, %d) => %d\n", a, b, NAIVE_MIN(a, b));

    printf("MAX(%d, %d) => %d\n", a, b, MAX(a, b));
    printf("MIN(%d, %d) => %d\n", a, b, MIN(a, b));

    printf("\nEverything fine so far...\n\n");

#pragma mark FATAL CASES:
    //cache:
    int _a = a;
    int _b = b;
    printf("NAIVE_MAX(%d++, %d++) => %d\n", _a, _b, NAIVE_MAX(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("NAIVE_MIN(%d++, %d++) => %d\n", _a, _b, NAIVE_MIN(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("NAIVE_MAX(++%d, ++%d) => %d\n", _a, _b, NAIVE_MAX(++a, ++b));

    //reset:
    a = _a;
    b = _b;
    printf("NAIVE_MIN(++%d, ++%d) => %d\n", _a, _b, NAIVE_MIN(++a, ++b));

    printf("\nOuch, this doesn't look right at all!\n\n");

#pragma mark NON-FATAL CASES:
    //reset:
    a = _a;
    b = _b;
    printf("MAX(%d++, %d++) => %d\n", _a, _b, MAX(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("MIN(%d++, %d++) => %d\n", _a, _b, MIN(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("MAX(++%d, ++%d) => %d\n", _a, _b, MAX(++a, ++b));

    //reset:
    a = _a;
    b = _b;
    printf("MIN(++%d, ++%d) => %d\n", _a, _b, MIN(++a, ++b));

    printf("\nAh, much better now.\n\n");

    return 0;
}

Console log:

NAIVE_MAX(3, 5) => 5
NAIVE_MIN(3, 5) => 3
MAX(3, 5) => 5
MIN(3, 5) => 3

Everything fine so far...

NAIVE_MAX(3++, 5++) => 6
NAIVE_MIN(3++, 5++) => 4
NAIVE_MAX(++3, ++5) => 7
NAIVE_MIN(++3, ++5) => 5

Ouch, this doesn't look right at all!

MAX(3++, 5++) => 5
MIN(3++, 5++) => 3
MAX(++3, ++5) => 6
MIN(++3, ++5) => 4

Ah, much better now.

So never ever use the naive implementation as seen in the code above (and as suggested by Brandon Bodnár, sorry buddy ;) ) if you want to avoid worst cases like these.

Repulsive answered 21/6, 2010 at 12:32 Comment(0)
D
17

Since you aren't using the OS X Implementation of objective-c, you may not have access to the predefined MIN and MAX macros.

You can define these yourself as

#define MIN(a,b)    ((a) < (b) ? (a) : (b))
#define MAX(a,b)    ((a) > (b) ? (a) : (b))

There is probably a better way to define them, but these will create the simple macros for your use. You can add them into any common .h file that your classes normally share.

Deflexed answered 23/1, 2010 at 23:51 Comment(1)
These are to be used with a grain of salt. MIN(i++, j++) for example does not result the expected. See my answer for details and solution.Repulsive
G
6

This is probably not a good idea for this particular application, but it is possible to write Objective-C methods with parameters “without names”, or rather with zero-length names:

+ min:(int)a :(int)b;
...
[Utils min:a :b]

(The selector would be @selector(min::).)

Geronto answered 24/1, 2010 at 0:18 Comment(0)
D
2

Objective-C class methods use named parameters, period. That's just the way it is.

Why not make it a global, free function? You shouldn't need a Utils class for this kind of thing.

If you don't want to clutter the global namespace, you could use Objective-C++ (rename all .m files to .mm) and put it in a namespace.

Dubai answered 23/1, 2010 at 23:22 Comment(0)
B
0

In a template file named "XXIntegerMath.h" drop this...

#import <Foundation/Foundation.h>

static inline NSInteger imax(NSInteger a, NSInteger b) {
    return  a > b ? a : b;
}

static inline NSInteger imin(NSInteger a, NSInteger b) {
    return  a < b ? a : b;
}

Then in your objective-c class ...

#import "XXIntegerMath.h"
NSInteger minValue = imin(someValue, someOtherValue);

It doesn't suffer from the problems described by Regexident.

Birddog answered 30/7, 2014 at 11:11 Comment(0)
B
0

Here is a macro I created for multi-max and multi-min which allows more than just 2 inputs.

float a = MMAX(1,2,9.33,2.5); //a = 9.33

The internal mechanisms use long double and you'll just cast the output to whatever variable you're using. I'd prefer a solution using typeof but couldn't figure out how to do it on __VA_ARGS__ on a per argument basis, maybe someone more versed than me in C can figure it out and comment? Anyways, here's the macro definition:


#define MMAX(...) ({\
long double __inputs[(sizeof((long double[]){__VA_ARGS__})/sizeof(long double))] = {__VA_ARGS__};\
long double __maxValue = __inputs[0];\
for (int __i = 0; __i < (sizeof((long double[]){__VA_ARGS__})/sizeof(long double)); ++__i) {\
long double __inputValue = __inputs[__i];\
__maxValue = __maxValue>__inputValue?__maxValue:__inputValue;\
}\
__maxValue;\
})

#define MMIN(...) ({\
long double __inputs[(sizeof((long double[]){__VA_ARGS__})/sizeof(long double))] = {__VA_ARGS__};\
long double __minValue = __inputs[0];\
for (int __i = 0; __i < (sizeof((long double[]){__VA_ARGS__})/sizeof(long double)); ++__i) {\
long double __inputValue = __inputs[__i];\
__minValue = __minValue<__inputValue?__minValue:__inputValue;\
}\
__minValue;\
})
Bodhisattva answered 4/4, 2020 at 4:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.