www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Circle Calculator Help

reply "Alexander" <alexander alexandermohn.com> writes:
Hello everybody!

I am new to D, and I am working on a program that calculates the 
area and circumference of a circle. However, when I compile it 
and run it, it waits for the user to input the radius, but then 
it closes while displaying a bunch of stuff.
I've tried several ways to get it to wait, but none of them work.

Here's my latest code:

//Written in the D programming language! (Which rocks by the way!)
//Import the necessary modules
import std.stdio;
import std.math;
import std.conv;
import std.string;

//Welcome the user
int welcome()
{
	writefln ("Welcome to the Circle Calculator!");
	return 0;
}

//Ask for the radius
float askradius()
{
	char[] number;
	float radius;
	writefln ("What is the radius of your circle?\n");
	stdin.readln(number);
	radius = to!float(number);
	//Put the radius into a variable
	return radius;
}

//Show the user the results
void result()
{
	writefln ("The area is:", area());
	writefln ("The circumference is:", cir());
}

//Wait
void wait()
{
	writefln ("Type A to continue!");
	exittest();
}

//Exit tester
void exittest()
{
	char[] a;
	stdin.readln(a);
	if (a == "A")
	{
		exit();
	}
	else
	{
		wait();
	}
}

//Loop escape
void exit()
{
}

//Define pi
float pi()
{
	float pi = 3.14159265358979323;
	return pi;
}

//Calculate the square of the radius (for the area)
float sqradius()
{
	float sqradius = askradius() * askradius();
	return sqradius;
}

//Calculate area
float area()
{
	float area = pi() * sqradius();
	return area;
}

//Calculate double the radius (for the circumference)
float dbradius()
{
	float dbradius = askradius() * 2;
	return dbradius;
}

//Calculate circumference
float cir()
{
	float cir = pi() * dbradius();
	return cir;
	
}

void main()
{
	welcome();
	askradius();
	dbradius();
	sqradius();
	area();
	cir();
	result();
	wait();
}

How should I fix this so it will wait for the user to press a key 
to exit?

Thanks a ton!

-Alexander
	
Jun 26 2012
next sibling parent "Alexander" <alexander alexandermohn.com> writes:
By the way, this is just my 2nd program in D.
It is just for fun, and I'm doing it to practice using this 
language.

This is normally how I teach myself languages.
I write a simple one then a more complex one on and on until I'm 
fluent in the language.
I don't have the book (but I'll get it soon), and I've just tried 
to use online references for this so far.

Thanks again!
Jun 26 2012
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
You should be able to just do a readln() before exiting
to give the user a chance to read everything, and hit
enter to exit.
Jun 26 2012
prev sibling next sibling parent "Alexander" <alexander alexandermohn.com> writes:
On Tuesday, 26 June 2012 at 14:53:33 UTC, Adam D. Ruppe wrote:
 You should be able to just do a readln() before exiting
 to give the user a chance to read everything, and hit
 enter to exit.

I just tried that, and it still closed right after I typed the radius. It looks almost like error code that pops up, but it closes so fast there's no way I could possibly read it.
Jun 26 2012
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 26 Jun 2012 10:40:18 -0400, Alexander  
<alexander alexandermohn.com> wrote:

 Hello everybody!

 I am new to D, and I am working on a program that calculates the area  
 and circumference of a circle. However, when I compile it and run it, it  
 waits for the user to input the radius, but then it closes while  
 displaying a bunch of stuff.

I'm assuming you are running on Windows. Windows with console output will allocate a console, and destroy the console after the program is finished. If you want it to keep the console up, start the command line interpreter (cmd.exe) before-hand and then run the program from within the console. Then all the output stays put.
 //Wait
 void wait()
 {
 	writefln ("Type A to continue!");
 	exittest();
 }

 //Exit tester
 void exittest()
 {
 	char[] a;
 	stdin.readln(a);
 	if (a == "A")
 	{
 		exit();
 	}
 	else
 	{
 		wait();
 	}
 }

Hm... interesting code here :) This is not horrible, just... weird. You probably want to avoid recursion in this case: void wait() { char[] a; while(a != "A") { writeln("Type A to continue!"); stdin.readln(a); } } -Steve
Jun 26 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/26/2012 09:43 PM, Steven Schveighoffer wrote:
 On Tue, 26 Jun 2012 10:40:18 -0400, Alexander
 <alexander alexandermohn.com> wrote:
 ...
 //Wait
 void wait()
 {
     writefln ("Type A to continue!");
     exittest();
 }

 //Exit tester
 void exittest()
 {
     char[] a;
     stdin.readln(a);
     if (a == "A")
     {
         exit();
     }
     else
     {
         wait();
     }
 }

Hm... interesting code here :) This is not horrible, just... weird.

It is functional style. ;)
 You probably want to avoid recursion in this case:

 void wait()
 {
     char[] a;
     while(a != "A")
     {
         writeln("Type A to continue!");
         stdin.readln(a);
     }
 }

 -Steve

I want the two examples to generate comparable code.
Jun 26 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/27/2012 01:40 AM, Steven Schveighoffer wrote:
 On Tue, 26 Jun 2012 19:10:25 -0400, bearophile
 <bearophileHUGS lycos.com> wrote:

 Steven Schveighoffer:

 I agree with Andrei, there is no outlet for errors in the to!T
 function, exception is the logical choice.

Maybe I was not clear enough, so let me explain a bit better. What I don't like is to!int("15\n") to be seen as an error in the first place. I'd like it to ignore leading and trailing whitespace, as in Python (stripping it automatically):

Right, but what if it's an error in your code if whitespace is present? Then you have to check for whitespace and throw your own error. I admit, that would likely be a rare occasion. But having both behaviors should be possible. ...

I think the default behaviour should be the behaviour that is wanted in the majority of cases.
Jun 26 2012
prev sibling next sibling parent "Alexander" <alexander alexandermohn.com> writes:
So, I've taken out the loop part that is "interesting" and 
replaced it with the readln() alternative.
However, I'm still getting what looks like an error.
I managed to take a screenshot of what pops up, and here is what 
it says:

std.conv.ConvException C:\D\dmd2\windows\bin\..\..\src\phobos\std\conv.d(1597):
Unexpected '
' when converting from type char[] to type float
-----------------
C:\D\dmd2\windows\bin\..\..\src\phobos\std\conv.d(1597): float 
std.conv.toImpl!(float, char[]).toImpl(char[])
C:\D\dmd2\windows\bin\..\..\src\phobos\std\conv.d(245): float 
std.conv.to!(float).to!(char[]).to(char[])
C:\Users\Alexander\Documents\D\circlecalc.d(23): float 
circlecalc.askradius()
C:\Users\Alexander\Documents\D\circlecalc.d(80): _Dmain
-----------------

Does anyone understand this error code?

I believe it means that it isn't letting me convert the user 
input into a floating number in function askradius().

How do I fix this?

(Just a note, the above part is popping up INSTEAD of what is 
supposed to pop up.)

Thanks!
Jun 26 2012
prev sibling next sibling parent "Alexander" <alexander alexandermohn.com> writes:
I'll probably put in this alternative:

 void wait()
 {
     char[] a;
     while(a != "A")
     {
         writeln("Type A to continue!");
         stdin.readln(a);
     }

Thanks!
Jun 26 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 26 Jun 2012 16:39:07 -0400, Alexander  
<alexander alexandermohn.com> wrote:

 So, I've taken out the loop part that is "interesting" and replaced it  
 with the readln() alternative.
 However, I'm still getting what looks like an error.
 I managed to take a screenshot of what pops up, and here is what it says:

 std.conv.ConvException C:\D\dmd2\windows\bin\..\..\src\phobos\std\conv.d(1597):
 Unexpected '
 ' when converting from type char[] to type float
 -----------------
 C:\D\dmd2\windows\bin\..\..\src\phobos\std\conv.d(1597): float  
 std.conv.toImpl!(float, char[]).toImpl(char[])
 C:\D\dmd2\windows\bin\..\..\src\phobos\std\conv.d(245): float  
 std.conv.to!(float).to!(char[]).to(char[])
 C:\Users\Alexander\Documents\D\circlecalc.d(23): float  
 circlecalc.askradius()
 C:\Users\Alexander\Documents\D\circlecalc.d(80): _Dmain
 -----------------

 Does anyone understand this error code?

Oh, readln includes the newline by default, so to!float is choking on that. Just remove the newline character: radius = to!float(strip(number)); (must import std.string) -Steve
Jun 26 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Steven Schveighoffer:

 Oh, readln includes the newline by default, so to!float is 
 choking on that.

Similar things happen often. But Andrei says this is good, because it's more orthogonal. As Sting, I don't subscribe to this point of view. Orthogonality isn't more important than practicality. Bye, bearophile
Jun 26 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 26 Jun 2012 17:17:29 -0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 Steven Schveighoffer:

 Oh, readln includes the newline by default, so to!float is choking on  
 that.

Similar things happen often. But Andrei says this is good, because it's more orthogonal. As Sting, I don't subscribe to this point of view. Orthogonality isn't more important than practicality.

I agree with Andrei, there is no outlet for errors in the to!T function, exception is the logical choice. But I also agree with you that if you don't care, it should be possible to ignore the errors without the cumbersome try-catch mechanism. Something like: to!(float, throw.No)(a) or toNoThrow!float(a) -Steve
Jun 26 2012
prev sibling next sibling parent "Alexander" <alexander alexandermohn.com> writes:
That must be why, I didn't import std.string!

Thanks!
Jun 26 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Steven Schveighoffer:

 I agree with Andrei, there is no outlet for errors in the to!T 
 function, exception is the logical choice.

Maybe I was not clear enough, so let me explain a bit better. What I don't like is to!int("15\n") to be seen as an error in the first place. I'd like it to ignore leading and trailing whitespace, as in Python (stripping it automatically):
 int("15\n")



So it's not a matter of ignoring the errors, but ignoring that leading and trailing whitespace. On the other hand, if you write to!dstring("15\n") this shouldn't strip away whitespace :-) So I understand Andrei motives too. To do that you have to hard-code different behaviors inside to!() according to the destination type. This is not so good.
 But I also agree with you that if you don't care, it should be 
 possible to ignore the errors without the cumbersome try-catch 
 mechanism.  Something like:

 to!(float, throw.No)(a)

 or

 toNoThrow!float(a)

What is it doing if you give it a wrong input string 'a'? This seems useful, but as you have seen it's different from what I was looking for. A non-throwing to!() may be handy to have: nullableTo!int("XX") => empty Nullable Nullable.get() is able to throw an exception. If you handle both empty and full cases of a nullable the D compiler is not able to statically infer that your code can't throw. You have to wrap that code into catching instructions any way, if you want your whole function (that uses nullableTo) to be nonthrow. Bye, bearophile
Jun 26 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 26 Jun 2012 19:10:25 -0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 Steven Schveighoffer:

 I agree with Andrei, there is no outlet for errors in the to!T  
 function, exception is the logical choice.

Maybe I was not clear enough, so let me explain a bit better. What I don't like is to!int("15\n") to be seen as an error in the first place. I'd like it to ignore leading and trailing whitespace, as in Python (stripping it automatically):

Right, but what if it's an error in your code if whitespace is present? Then you have to check for whitespace and throw your own error. I admit, that would likely be a rare occasion. But having both behaviors should be possible.
 int("15\n")



So it's not a matter of ignoring the errors, but ignoring that leading and trailing whitespace. On the other hand, if you write to!dstring("15\n") this shouldn't strip away whitespace :-) So I understand Andrei motives too. To do that you have to hard-code different behaviors inside to!() according to the destination type. This is not so good.

Options should be possible. I think probably we could even accept them like so: T to(T, U, Opts...)(U u, Opts opts) if(makesSenseAsToOpts!(T, U, Opts)) { ... } Then define options such as: enum TrimWhitespace : bool { Yes = true, No = false }
 But I also agree with you that if you don't care, it should be possible  
 to ignore the errors without the cumbersome try-catch mechanism.   
 Something like:

 to!(float, throw.No)(a)

 or

 toNoThrow!float(a)

What is it doing if you give it a wrong input string 'a'?

0. Similar to atoi That is, it consumes all leading numeric characters, and ignores the rest. I realize in hindsight this is no good for ignoring leading whitespace. Probably an option to ignore whitespace is better.
 This seems useful, but as you have seen it's different from what I was  
 looking for.

 A non-throwing to!() may be handy to have:

 nullableTo!int("XX") => empty Nullable

 Nullable.get() is able to throw an exception. If you handle both empty  
 and full cases of a nullable the D compiler is not able to statically  
 infer that your code can't throw. You have to wrap that code into  
 catching instructions any way, if you want your whole function (that  
 uses nullableTo) to be nonthrow.

This might be a good option too, but couldn't we just do: to!(Nullable!int)("XX") Many possibilities exist. -Steve
Jun 26 2012
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
On Jun 26, 2012, at 4:40 PM, Steven Schveighoffer wrote:

 On Tue, 26 Jun 2012 19:10:25 -0400, bearophile =

=20
 Steven Schveighoffer:
=20
 I agree with Andrei, there is no outlet for errors in the to!T =



=20
 Maybe I was not clear enough, so let me explain a bit better.
=20
 What I don't like is to!int("15\n") to be seen as an error in the =


 I'd like it to ignore leading and trailing whitespace, as in Python =


=20
 Right, but what if it's an error in your code if whitespace is =

error. to!int(trim("5\n")) no?=
Jun 26 2012
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 26 Jun 2012 19:44:34 -0400, Sean Kelly <sean invisibleduck.org>  
wrote:

 On Jun 26, 2012, at 4:40 PM, Steven Schveighoffer wrote:

 On Tue, 26 Jun 2012 19:10:25 -0400, bearophile  
 <bearophileHUGS lycos.com> wrote:

 Steven Schveighoffer:

 I agree with Andrei, there is no outlet for errors in the to!T  
 function, exception is the logical choice.

Maybe I was not clear enough, so let me explain a bit better. What I don't like is to!int("15\n") to be seen as an error in the first place. I'd like it to ignore leading and trailing whitespace, as in Python (stripping it automatically):

Right, but what if it's an error in your code if whitespace is present? Then you have to check for whitespace and throw your own error.

to!int(trim("5\n")) no?

That was my original suggestion. It fixes the problem, but can seem quite unintuitive to a developer that they have to do this. Plus if it actually *is* an error for the string to have whitespace, you would want it to throw. My point to bearophile is, we may want both options. I can easily see someone using just to!int(userInput), and testing without ever putting in spaces, and then user does and the application blows up (quite needlessly). -Steve
Jun 26 2012