www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - 'idiomatic' porting of c and or c++ code that does NULL checking

reply "nikki" <nikkikoole gmail.com> writes:
I am learning SDL by following the lazyfoo SDL2 tuorials, I am 
alos new to D so I have a question:

I the lazyfoo tutorials there are many functions that have a bool 
success whiich gets set at various places when something goes 
wrong to be returned afterwards.

http://lazyfoo.net/tutorials/SDL/02_getting_an_image_on_the_screen/index.php
for example:
[code]

bool init()
{
     //Initialization flag
     bool success = true;

     //Initialize SDL
     if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
     {
         printf( "SDL could not initialize! SDL_Error: %s\n", 
SDL_GetError() );
         success = false;
     }
     else
     {
         //Create window
         gWindow = SDL_CreateWindow( "SDL Tutorial", 
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, 
SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
         if( gWindow == NULL )
         {
             printf( "Window could not be created! SDL_Error: 
%s\n", SDL_GetError() );
             success = false;
         }
         else
         {
             //Get window surface
             gScreenSurface = SDL_GetWindowSurface( gWindow );
         }
     }

     return success;
}


[/code]


in my D code I just change the NULL into null and the printf to a 
fitting writeln.
But I am wondering if D offers me much cleaner ways of writing 
this, I am guessing the scope() but what would be the best/D way 
of writing this function?

How would you write it?
Aug 23 2014
next sibling parent "nikki" <nikkikoole gmail.com> writes:
Oops well writing the above post made me realise what to look for 
: http://dlang.org/errors.html
;)
Aug 23 2014
prev sibling next sibling parent reply ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Sat, 23 Aug 2014 10:19:58 +0000
nikki via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:

don't use '=3D=3D' to check for nulls. the right way is:

  if (foo is null) {}
  if (bar !is null) {}

'=3D=3D' transforms to opEquals call (see 'operator overloading') and 'is'
not.

as for 'best practice' question -- it depends of many things. ;-)
Aug 23 2014
next sibling parent reply "nikki" <nikkikoole gmail.com> writes:
On Saturday, 23 August 2014 at 10:29:04 UTC, ketmar via 
Digitalmars-d-learn wrote:
 On Sat, 23 Aug 2014 10:19:58 +0000
 nikki via Digitalmars-d-learn 
 <digitalmars-d-learn puremagic.com> wrote:

 don't use '==' to check for nulls. the right way is:

   if (foo is null) {}
   if (bar !is null) {}

 '==' transforms to opEquals call (see 'operator overloading') 
 and 'is'
 not.

 as for 'best practice' question -- it depends of many things. 
 ;-)
A good to know! thanks. I'd still be interrested to see the idiomatic D version of that function, what would that depend on ?
Aug 23 2014
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 23 August 2014 at 10:33:02 UTC, nikki wrote:
 A good to know! thanks.
 I'd still be interrested to see the idiomatic D version of that 
 function, what would that depend on ?
Honestly, I wouldn't change it much. If it didn't throw exceptions before, then it probably would have trouble handling them now. What I *would* do is use multiple returns though. This style of if/else invariably leads to the dreaded "diagonal line of death" (http://geekandpoke.typepad.com/geekandpoke/2009/12/geek-for-dummies-chapter-2.html) Once you've done that, any resource you'd have otherwise needed to Un-conditionally release, I'd do with a scope. bool init() { //Initialize SDL if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() ); return false; } //Create window gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN ); if( gWindow == NULL ) { printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() ); return false; } //Get window surface gScreenSurface = SDL_GetWindowSurface( gWindow ); return true; } Now, once you've adopted this kind of style, migrating to exceptions (should you so wish to do so) should much easier.
Aug 23 2014
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
ketmar:

 don't use '==' to check for nulls. the right way is:

   if (foo is null) {}
   if (bar !is null) {}

 '==' transforms to opEquals call (see 'operator overloading') 
 and 'is' not.
I use "is" and "!is" for class references and == != for pointers. But now I think you are right, and in D it's better to always use is and !is for both, to avoid present and future bugs (like when a pointer gets replaced by a class reference by successive changes in the code). So the code I've written becomes: bool initializeSDL() out { assert(.gWindow !is null); assert(.gScreenSurface !is null); } body { alias success = bool; if (SDL_Init(SDL.init_video) < 0) { stderr.writeln("SDL could not initialize! SDL_Error: ", SDL_GetError); return success(false); } else { .gWindow = SDL_CreateWindow("SDL Tutorial", SDL.qindowpos_undefined, SDL.windowpos_undefined, .screen_width, .screen_height, SDL.window_shown); if (.gWindow is null) { stderr.writeln("Window could not be created! SDL_Error: ", SDL_GetError); return success(false); } else { .gScreenSurface = SDL_GetWindowSurface(.gWindow); } } return success(true); } bool initializeSDL() nothrow out { assert(.gWindow !is null); assert(.gScreenSurface !is null); } body { if (SDL_Init(SDL.init_video) < 0) { throw new text("SDL could not initialize: ", SDL_GetError).SDL_Error; } else { .gWindow = SDL_CreateWindow("SDL Tutorial", SDL.qindowpos_undefined, SDL.windowpos_undefined, .screen_width, .screen_height, SDL.window_shown); if (.gWindow is null) { throw new text("Window could not be created: ", SDL_GetError).SDL_Error; } else { gScreenSurface = SDL_GetWindowSurface(gWindow); } } } Bye, bearophile
Aug 23 2014
parent reply ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Sat, 23 Aug 2014 10:53:03 +0000
bearophile via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
wrote:

 I use "is" and "!is" for class references and =3D=3D !=3D for pointers.=20
 But now I think you are right, and in D it's better to always use=20
 is and !is for both, to avoid present and future bugs (like when=20
 a pointer gets replaced by a class reference by successive=20
 changes in the code).
and "foo is null" is nice to read. ;-)
Aug 23 2014
next sibling parent reply "Kagamin" <spam here.lot> writes:
On Saturday, 23 August 2014 at 11:07:23 UTC, ketmar via 
Digitalmars-d-learn wrote:
 and "foo is null" is nice to read. ;-)
Meh, looks like a guest from pascal or basic.
Aug 23 2014
parent ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Sat, 23 Aug 2014 15:10:22 +0000
Kagamin via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
wrote:

 Meh, looks like a guest from pascal or basic.
so let's replace writeln() with %&^#$#%^& then. this looks like a function name for Real Hackers.
Aug 23 2014
prev sibling parent "Kagamin" <spam here.lot> writes:
On Saturday, 23 August 2014 at 11:07:23 UTC, ketmar via 
Digitalmars-d-learn wrote:
 and "foo is null" is nice to read. ;-)
function bool init begin rem Initialization flag bool success assign true; rem Initialize SDL if execute SDL_Init SDL_INIT_VIDEO lt 0 begin execute printf "SDL could not initialize! SDL_Error: %s\n", execute SDL_GetError; success assign false; end else begin rem Create window gWindow assign execute SDL_CreateWindow "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN; if gWindow is NULL begin execute printf "Window could not be created! SDL_Error: %s\n", execute SDL_GetError; success assign false; end else begin rem Get window surface gScreenSurface assign execute SDL_GetWindowSurface gWindow; end; end; return success; end; Couldn't resist... :)
Aug 23 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
nikki:

 How would you write it?
I don't know how much idiomatic this is, but you can start cleaning up the code: - Renaming the function with something more clear; - using a D enumeration for the various constants. - I have used a "." before the module-level variables to denote better they are not local; - I have used an alias and stderror. - All the code below is untested. bool initializeSDL() out { assert(.gWindow != null); assert(.gScreenSurface != null); } body { alias success = bool; if (SDL_Init(SDL.init_video) < 0) { stderr.writeln("SDL could not initialize! SDL_Error: ", SDL_GetError); return success(false); } else { .gWindow = SDL_CreateWindow("SDL Tutorial", SDL.qindowpos_undefined, SDL.windowpos_undefined, screen_width, screen_height, SDL.window_shown); if (.gWindow == null) { stderr.writeln("Window could not be created! SDL_Error: ", SDL_GetError); return success(false); } else { .gScreenSurface = SDL_GetWindowSurface(.gWindow); } } return success(true); } In D error messages are often given by throwing errors, so this looks a little more idiomatic: bool initializeSDL() nothrow out { assert(.gWindow != null); assert(.gScreenSurface != null); } body { if (SDL_Init(SDL.init_video) < 0) { throw new text("SDL could not initialize: ", SDL_GetError).SDL_Error; } else { .gWindow = SDL_CreateWindow("SDL Tutorial", SDL.qindowpos_undefined, SDL.windowpos_undefined, screen_width, screen_height, SDL.window_shown); if (.gWindow == null) { throw new text("Window could not be created: ", SDL_GetError).SDL_Error; } else { gScreenSurface = SDL_GetWindowSurface(gWindow); } } } If you can add some more function attributes, like safe. Bye, bearophile
Aug 23 2014
prev sibling next sibling parent "hane" <han.ehit.suzi.0 gmail.com> writes:
On Saturday, 23 August 2014 at 10:19:59 UTC, nikki wrote:
 I am learning SDL by following the lazyfoo SDL2 tuorials, I am 
 alos new to D so I have a question:

 I the lazyfoo tutorials there are many functions that have a 
 bool success whiich gets set at various places when something 
 goes wrong to be returned afterwards.

 http://lazyfoo.net/tutorials/SDL/02_getting_an_image_on_the_screen/index.php
 for example:
 [code]

 bool init()
 {
     //Initialization flag
     bool success = true;

     //Initialize SDL
     if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
     {
         printf( "SDL could not initialize! SDL_Error: %s\n", 
 SDL_GetError() );
         success = false;
     }
     else
     {
         //Create window
         gWindow = SDL_CreateWindow( "SDL Tutorial", 
 SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, 
 SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
         if( gWindow == NULL )
         {
             printf( "Window could not be created! SDL_Error: 
 %s\n", SDL_GetError() );
             success = false;
         }
         else
         {
             //Get window surface
             gScreenSurface = SDL_GetWindowSurface( gWindow );
         }
     }

     return success;
 }


 [/code]


 in my D code I just change the NULL into null and the printf to 
 a fitting writeln.
 But I am wondering if D offers me much cleaner ways of writing 
 this, I am guessing the scope() but what would be the best/D 
 way of writing this function?

 How would you write it?
How about this? ---- import std.exception; // enforce() is declared in std.exception void init() { // enforce() throws an exception if condition is false enforce(SDL_Init( SDL_INIT_VIDEO ) >= 0, "SDL could not initialize!"); // enforce() throws if SDL_CreateWindow returns null gWindow = SDL_CreateWindow(/* ... */).enforce("Window could not be created!"); // ditto gScreenSurface = SDL_GetWindowSurface(gWindow).enforce("Surface could not be created!"); } ----
Aug 23 2014
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On 8/23/2014 7:19 PM, nikki wrote:

 How would you write it?
``` // Put this somewhere you can import it into any module calling SDL class SDLError : Error { public this( string msg, string file = __FILE__, size_t line = __LINE__ ) { import std.string; import std.conv; import derelict.sdl2.sdl; auto fmsg = format( "%s: %s", msg, to!string( SDL_GetError() )); super( fmsg, file, line, null ); } } void init() { //Initialize SDL if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { throw new SDL_Error( "Failed to init SDL" ); } //Create window gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN ); if( !gWindow ) { throw new SDLError( "Failed to create window" ); } //Get window surface gScreenSurface = SDL_GetWindowSurface( gWindow ); } ``` Regarding 'is' vs == for equality, I prefer to use the latter with pointers returned from C so that I can keep in mind that it actually is something given to me from C and is not managed by the GC. I can tell at a glance. --- This email is free from viruses and malware because avast! Antivirus protection is active. http://www.avast.com
Aug 24 2014
parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Monday, 25 August 2014 at 02:17:47 UTC, Mike Parker wrote:
 // Put this somewhere you can import it into any module calling
Small modification for even terser error handling: T sdlEnforce(T)(T result, string message = null) { if (!result) throw new SdlException("SDL error: " ~ (message ? message ~ ": " : "") ~ to!string(SDL_GetError())); return result; } Usage: gWindow = SDL_CreateWindow(...).sdlEnforce("SDL_CreateWindow");
 class SDLError : Error {
This is misuse of the Error class. Don't do this, subclass Exception instead. D errors should be used to indicate logic errors (conditions that can only arise from a bug in the program), not failures in 3rd-party libraries.
Aug 24 2014
parent reply Mike Parker <aldacron gmail.com> writes:
On 8/25/2014 11:35 AM, Vladimir Panteleev wrote:
 On Monday, 25 August 2014 at 02:17:47 UTC, Mike Parker wrote:
 // Put this somewhere you can import it into any module calling
Small modification for even terser error handling: T sdlEnforce(T)(T result, string message = null) { if (!result) throw new SdlException("SDL error: " ~ (message ? message ~ ": " : "") ~ to!string(SDL_GetError())); return result; } Usage: gWindow = SDL_CreateWindow(...).sdlEnforce("SDL_CreateWindow");
 class SDLError : Error {
This is misuse of the Error class. Don't do this, subclass Exception instead. D errors should be used to indicate logic errors (conditions that can only arise from a bug in the program), not failures in 3rd-party libraries.
I use Exception for recoverable errors and Error for those that aren't. --- This email is free from viruses and malware because avast! Antivirus protection is active. http://www.avast.com
Aug 24 2014
parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Monday, 25 August 2014 at 03:19:09 UTC, Mike Parker wrote:
 I use Exception for recoverable errors and Error for those that 
 aren't.
Sorry, you're right, that description of Exception/Error is correct. But I don't think that SDL initialization is a non-recoverable error. The program might want to retry SDL initialization with different parameters, and if that code would make it into a library, said library might try using a different graphics library or use some other form of user interaction.
Aug 26 2014
next sibling parent reply "eles" <eles215 gzk.dot> writes:
On Wednesday, 27 August 2014 at 05:39:59 UTC, Vladimir Panteleev 
wrote:
 On Monday, 25 August 2014 at 03:19:09 UTC, Mike Parker wrote:
 Sorry, you're right, that description of Exception/Error is 
 correct. But I don't think that SDL initialization is a 
 non-recoverable error. The program might want to retry SDL 
 initialization with different parameters
While this may be true in this case, I think that, in general, you cannot draw such a clear line between what's recoverable and what's not. If you really want to push things to the extreme, the sole unrecoverable error shall be assertion failure and the SIGKILL. Everything else could be otherwise handled, even if for that you'd need to program a new operating system inside your program, just because the one that intend to use is missing ;) No, that's extreme. But, matter is, what is recoverable and what not, is a matter of what the architect (and the specification) decide to be.
Aug 26 2014
next sibling parent "eles" <eles215 gzk.dot> writes:
On Wednesday, 27 August 2014 at 05:45:34 UTC, eles wrote:
 On Wednesday, 27 August 2014 at 05:39:59 UTC, Vladimir 
 Panteleev wrote:
 On Monday, 25 August 2014 at 03:19:09 UTC, Mike Parker wrote:
 failure and the SIGKILL.
(and SIGKILL just because you cannot catch it, otherwise you could yell at the user...)
Aug 26 2014
prev sibling parent "Dominikus Dittes Scherkl" writes:
On Wednesday, 27 August 2014 at 05:45:34 UTC, eles wrote:
 While this may be true in this case, I think that, in general, 
 you cannot draw such a clear line between what's recoverable 
 and what's not. If you really want to push things to the 
 extreme, the sole unrecoverable error shall be assertion 
 failure and the SIGKILL.
That's exactly the line I would draw. _Nothing_ else is an error, so _everything_ is an exception. Best forget about that something else even exist.
Aug 26 2014
prev sibling parent Mike Parker <aldacron gmail.com> writes:
On 8/27/2014 2:39 PM, Vladimir Panteleev wrote:
 On Monday, 25 August 2014 at 03:19:09 UTC, Mike Parker wrote:
 I use Exception for recoverable errors and Error for those that aren't.
Sorry, you're right, that description of Exception/Error is correct. But I don't think that SDL initialization is a non-recoverable error. The program might want to retry SDL initialization with different parameters, and if that code would make it into a library, said library might try using a different graphics library or use some other form of user interaction.
It is entirely reasonable for someone to decide that failure to init SDL is an unrecoverable error, while failure to create a window is not, or that both are or neither is. I don't see that any one of the these approaches is set in stone, or that it even need be the same from project to project. The way I structure my code in the little rinky-dink projects scattered about my hard drive, any failure in initializing required systems (like graphics) is an Error, whereas init failure for noncritical systems (like audio) is an Exception. The former I let filter to a top-level handler where I log them and exit, the latter I catch and respond where appropriate. I would very likely take a different approach were I developing a library for public consumption so that the user can decide. --- This email is free from viruses and malware because avast! Antivirus protection is active. http://www.avast.com
Aug 27 2014