TweetFollow Us on Twitter

Apple's C++
Volume Number:5
Issue Number:11
Column Tag:Jörg's Folder

Apple's C++

By Jörg Langowski, MacTutor Editorial Staff

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

“C++”

OOPS has taken its literal meaning with the brief C++ introduction that I wrote 2 months ago now that I have a compiler to test the examples that I thought up. Of course, I did it all wrong. Seasoned C++ experts might have smiled when they read my ‘matrix class’ definitions, others (like myself) might not have noticed the goofups at all. Anyway, this month you’ll find much more detailed examples of the same kind, and I can assure you they work, because they’ve been tested. [Before you cancel your subscription in panic, let me emphasize that the overview of C++ in the same article is still basically correct].

Someone on the networks came up with this quote: “C++ is the Forth of the 90’s - they don’t call it ‘uh-oh programming’ for nothing”. Well, I can confirm on the uh-oh part, and as far as the Forth is concerned, at least I’m learning this language as much by trial and error as I did with Forth. So let’s follow the learning curve together; maybe that is not such a bad approach for a tutorial.

Our example is an MPW tool that does some array computations using a matrix and vector class that have a number of methods defined. We’ll go through the example step by step, and learn some important features of data structure definition in C++. The program is not Mac-specific; it uses only the standard C++ libraries, so you can check out the examples on a UNIX machine with C++ even if you don’t have access to Apple’s C++ (and if you do, chances are that you might not need this tutorial at all).

Simple I/O in C++

The first few lines of our example - after the #includes - define a simple error message function which writes a string to standard error and exits the program. The definition looks very much like C except for the line

 cerr << p << endl;

which is a C++ I/O statement that writes the string p to standard error. cerr is an object of class ostream which is basically an output file; cerr is predefined to be the standard error output for a UNIX system or for MPW. Likewise, cin and cout are predefined standard input and output (console). << is the output operator, and to write an object x to standard output you simply write

 cout <<  x;

Whether the compiler will accept this statement or not depends whether the operator << has been defined for the type x. Standard definitions for most simple types are contained in the header file Stream.h. The operator >> is the input operator:

 cin >> i;

would read the int i from standard input. endl is used to flush the output buffer (otherwise the actual output might appear on the screen at a later time), and add an end-of-line.

The Vector Class

In the following, we define a class vector, a resizeable one-dimensional array of float with optional range checking. Its private variables are float* v, which will be used as a pointer to the data, and int sz, the number of elements in the vector.

We then declare the class matrix (defined further down) as a friend of vector. Why this? Later, we will define an operator which multiplies a matrix with a vector as a method of the class matrix. This operator needs access to the data contained in the vector. Since the normal way of accessing involves bounds checking and is therefore slow, we want to be able to access the ‘private part’ v of the vector directly. Friends of a class may do this.

The publicly accessible parts of the class are all the methods defined for our vector:

• the constructors, vector(int) and vector(vector&); the first one creates a new vector given its size as an argument, the second one duplicates an existing vector by creating a new one of the same size and copying all the elements;

• the destructor, ~vector(), which will free the space allocated to the object’s data when the object is no longer needed;

• size(), an inline function that returns the length of the vector;

• set_size(int), which changes the size of an existing vector;

• the indexing operator [], for accessing an element of the vector. We have to note here that the operator returns a reference to a float, not a float value, so that an indexed element can be used on both sides of an assignment statement. [] will check the index against the bounds of the vector;

• elem(int i), an inline function which returns the value of the i-th element of the vector without range checking, for fast access;

• the operators =, +, and -, which are used for assignment and elementwise addition or subtraction of vectors. They will check whether the vectors on both sides of the operator sign are of equal size, perform the operation, and return the reference to a newly created vector which contains the result;

• the operator *, which computes the scalar product of two vectors, and returns a float value;

• print(), which prints out the contents of the vector to cout.

The class definition constitutes the interface to the object’s structure and its methods; the actual implementation follows.

I have put informative messages into the constructor and destructor methods so that one can see how new objects are created and released. This is important for debugging; if less objects are released than created, something might have gone wrong, and at least one has wasted memory space.

vector(size) creates an array of floats on the heap that is size elements long. vector(a), where a is another vector, will create a new vector which is an exact copy of a. These constructors are called when new vectors are defined:

vector x(5); // calls vector(int)
vector y = x;  // calls vector(vector&)

In the for statement you see another characteristic feature of C++: declarations can be made anywhere, so the loop index i may be declared as a register variable just for the scope of the loop.

The destructor ~vector() is called when an instance of vector goes ‘out of scope’, and deletes the space allocated for the array v before the object itself is deleted. Defining a destructor is usually done when you have allocated some of your own memory on construction, just as we did.

The operator [] will first see if the index is within the limits of the array and abort with an error message if not (this could be done in a more sophisticated way); then it indexes the private array v and returns a reference to its i-th element. Note that the operator [], when used with v, will be the usual array indexing function; when used on a vector, it uses range checking, since its original definition has been overloaded. If we define a function or an operator with the same name as an existing one, old definitions will automatically be overloaded in C++ 2.0; the overload statement of the previous version described in Stroustrup’s book is not necessary anymore.

The assignment operator will copy all elements of the argument vector into its parent vector, making sure that both are of the same size. It returns a reference to the argument vector, so that multiple assignment statements are possible:

 a = b = c; // copies c into b and a

+ and - create a new vector of the same size as of its arguments and copies the sum of the two vectors into it. The new vector is allocated on the heap, using the new operator:

 vector& c = *new vector(sz);

that is, we define a reference c to a vector, to which we assign the pointer to the new vector. One could think that one could simply create a new instance by writing

 
vector c(sz);

however, this will only create a local instance of vector, which will be deleted as soon as the function is left. The compiler, by the way, complains if you use a local object as the return value (just as a warning, it will still compile ). Rightly so, since local objects are allocated in a local stack frame, and disappear as soon as that stack frame is UNLKed and the JSR called.

Therefore, we must create a new vector in the heap which will hold the result of the addition or subtraction. This will later require some housekeeping on our part, because a heap object is not automatically deleted when its scope is left. We must take care of that ourselves (see below).

The definition of the scalar product, *, and the print() function should now be self-explanatory. I have not given a definition for the resizing function, set_size(int); try whether you can come up with a definition for it.

The Matrix Class

Contrary to what I wrote in the September column, we won’t define matrix as a class derived from vector. Also, we won’t define matrix as an array of vectors; I had tried this approach, which is very elegant when it works, but screwed up so completely that I haven’t come up with a solution as the deadline is approaching. Therefore, we’ll use a simpler definition, which has the advantage of being faster than what I thought up before.

Thus: class matrix has the private variables mv, a pointer to an array of floats, and the two integers rows and cols, which indicate the number of rows and columns in the array. We will do our index calculations explicitly in the methods of matrix and use one-dimensional indexing for actually accessing the elements of mv within the method. To the outside, this is not visible and we’ll always use two-dimensional indexing with range checking.

The methods defined are:

• constructors and a destructor, analogous to those of class vector;

• two functions that return the number of rows and columns of the matrix (note that rowsize should not be read as ‘size of one row’, but ‘size in units of rows’);

• set_size, unimplemented as for vector, left for you as an exercise;

• the two-dimensional indexing operator (), which takes two ints i,j as arguments and returns a reference to the (i,j)-th element. Thus, we won’t use square brackets for indexing: instead of a[i][j] like in C we’ll write a(i,j) like in Fortran. This is an overload of the function call operator () which was not possible in version 1 of C++, but is legal in C++ 2.0. Any operator may be redefined in C++ 2.0, including the comma.

• the quick indexing function elem(i,j), which returns the value of the (i,j)-th element without bounds checking;

• the assignment, addition and subtraction operators, which work analogously to those for vectors;

• two multiplication operators, one for multiplying two matrices, one for multiplying a vector by a matrix from the left;

• the print() function.

The method definitions follow the class declaration, and you should now be able to go through them without much explanation. The matrix*vector operator accesses the data of the vector argument a directly (a.v[j]); it is for this reason that we made matrix a friend of vector. We could have achieved the same result without the friend declaration by using the inline indexing function a.elem(j), but the inline expansion of function is not guaranteed in all implementations.

The Main Program

Using matrix operations in the main program has now become very simple and easy to read. For instance, the statement

 matrix& x = a*c;

will compute the matrix product of a and c (given that the dimensions are correct such that the product can be computed), put the result into a new matrix allocated on the heap and make the reference x point to that matrix. From now on, x can be used whenever an object of type matrix is required; x.print(), for instance, prints the contents of x. The only thing that we have to be careful about is to delete all ‘hidden instances’ explicitly at the end of the block in which they have been created:

 delete &x; delete &f;

The compiler will also issue warnings here, presumably because x and f might not be references to heap objects, and the delete statements might crash at run time.

More complicated statements like

 matrix& x = (a + b)*c;

might leave intermediate results on the heap to which there is no more access. Some sort of a garbage collector would be needed to clean up those objects; I don’t know whether something is planned in that direction. For the time being, you can always break up such lines into multiple statements and assign any intermediate result explicitly to a reference variable, which can be deleted later.

If you run the example - and we include the MPW tool on the source code disk for those who have no C++ compiler available - you’ll notice how instances of vectors and matrices are created and deleted, and how the product matrix A*C automatically comes out the correct size.

In the future, I am planning to implement a whole library of matrix functions in C++; maybe we’ll have a follow-up on this article some time. In the next part of the tutorial, we’ll deal with Mac-style programming, we’ll define a simple application class with an event loop and event handlers.

Apple’s C++

Although I haven’t covered Macintosh-specific details this month, let me just mention the fact that the examples given here were compiled using a test version of the Apple MPW C++ compiler. This compiler is based upon the AT&T C++ Language System, which is a pre-compiler that generates C code from a C++ source. The C code can then be compiled into machine code by any C compiler. This strategy was taken so that the C++ system could be quickly implemented on any machine running C.

The actual version of AT&T C++ is 2.0, and deviates from the description in Bjarne Stroustrup’s book. A number of features have been added, which I have partially covered already. As we encounter them in the course of these tutorials, we’ll learn more about the changes in C++ 2.0 with respect to the book.

Feedback dept.

“Dear Jörg,

Thank you for your interesting article on compilers in August MacTutor. I feel very little attention has been paid to the quality of the code produced by Mac compilers. I have been porting some FORTRAN code using LSF 1.2 to the MacII and have been very embarrassed by IBM’ers when comparing execution speed on their 16MHz 386 machines - due purely to the much better optimization of MS-DOS FORTRAN compilers [Having used Lahey Fortran 77 on a 286 machine, I can only agree with you - jl].

I was also very disappointed when Apple released MPW 3.0 to find that their C compiler produced code significantly slower than the old 2.0 C compiler from Green Hills. For example the old 2.0 compiler ran your benchmarks (as written) in 3.8 (non opt) and 2.8 (opt) secs respectively. Using pointers instead of indexing in the inner loop reduced that to 2.46 secs. Happily one can use the 2.0 compiler as a tool under 3.0 for those time critical routines and mix 2.0 and 3.0 object code as long as you follow certain rules [Summarize those rules for us and write us about it, this is interesting - jl].

I suppose you have had your attention drawn to the bugs in the C code, but just in case

• C arrays index from 0 so you were overwriting memory when addressing index[50][50] in your C routine!

[True! What shall I say except the remarks about learning curves that I made in the beginning ]

• C and Pascal arrays are reversed as compared to FORTRAN. i.e. A(20,30) in FORTRAN should be declared A[30][20] in C. It follows from this that for correct addressing the arrays in the C parameter list should be declared a[][50], not a[50][]. I found that if you correct this then the C non-pointer routines are significantly slowed down even more!

Andrew Cunningham, Mona Vale, NSW, Australia”

[The historical reason for the unsatisfactory optimization of most Macintosh compilers is probably that in the beginning most people were so glad to have any compiler at all that they did not pay much attention to the quality of the code as long as the stuff ran at all. Also, the toolbox calls are always the same, so it doesn’t really matter whether your code is well-optimized or not as long as you mainly use toolbox calls and not doing any involved computations. Hopefully, the impact of the MacII in the scientific/engineering sector is strong enough to create some pressure on compiler writers to provide optimal tools - jl]

On the network:

Date: Fri, 8 Sep 89 10:18:24 CDT

From: “Bob Loewenstein” <rfl@oddjob.uchicago.edu>

To: Langowski%frembl51.bitnet@tank.uchicago.edu

Subject: Neon

I talked briefly with Kriya and it looks like they will put it into the public domain shortly. - Bob

[Very good! We’re all looking forward to it!]

See you again next month.

Listing 1: Matrix operations in C++

#include <String.h>
#include <Stream.h>
#include <StdLib.h>

void error (char* p)
{
 cerr << p << endl;
 exit(1);
}

class vector 
{
 float* v;
 int sz;
 friend matrix;
 
public:
 vector(int);
 vector(vector&); 
 ~vector();
 int size () { return sz; }
 void set_size(int);
 float& operator[](int);
 float elem(int i) { return v[i]; }
 vector& operator= (vector&); // assignment
 float operator* (vector&); // scalar product
 vector& operator+ (vector&); // elementwise addition
 vector& operator- (vector&); // and subtraction
 void print(); 

};

vector::vector (int size)
{
 cout << “constructing vector object” << endl;
 if (size<=0) 
 { v = 0; return; }
 sz = size;
 v = new float[sz];
}

vector::vector (vector& a)
{
 cout << “copying vector object” << endl;
 sz = a.sz;
 v = new float[sz];
 for (register int i=0 ; i<sz ; i++)
 v[i] = a.v[i];
}

vector::~vector ()
{
 cout << “deleting vector object” << endl;
 delete v;
}

float&
vector::operator[] (int i)
{
 if (i<0 || i>= sz) 
 error(“class vector: index out of range”);
 return v[i]; 
}

vector&
vector::operator= (vector& a)
{
 if (a.sz != sz)
 error(“class vector: size mismatch in =”);
 for (register int i=0 ; i<sz ; i++)
 v[i] = a.v[i];
 return a;
}

vector&
vector::operator+ (vector& a)
{
 if (sz != a.sz)
 error(“class vector: size mismatch in +”);
 vector& c = *new vector(sz);
// DON’T USE vector c(sz); 
// this would be destroyed on exiting the method
 for (register int i=0 ; i<sz ; i++)
 c.v[i] = v[i]+a.v[i];
 return c;
}

vector&
vector::operator- (vector& a)
{
 if (sz != a.sz)
 error(“class vector: size mismatch in +”);
 vector& c = *new vector(sz);
 for (register int i=0 ; i<sz ; i++)
 c.v[i] = v[i]-a.v[i];
 return c;
}

float
vector::operator* (vector& a)
{
 if (sz != a.sz)
 error(“class vector: size mismatch in *”);
 float sum = 0;
 for (register int i=0 ; i<sz ; i++)
 sum = sum + v[i]*a.v[i];
 return sum;
}

void
vector::print()
{
 for (int i=0; i<sz-1; i++)
 cout << v[i] << “ | “;
 cout << v[sz-1] << endl;
}

class matrix
{
    float* mv;
 int rows, cols;
  
public:
 matrix(int,int); 
 matrix(matrix&);
 ~matrix();
 int rowsize () { return rows; }
 int colsize () { return cols; }
 void set_size(int,int);
 float& operator()(int,int);
 float elem(int i, int j) { return mv[i*cols + j]; }
 matrix& operator= (matrix&); // assignment
 matrix& operator+ (matrix&); // elementwise addition
 matrix& operator- (matrix&); // elementwise subtraction
 matrix& operator* (matrix&); // matrix product
 vector& operator* (vector&); // matrix*vector
 void print();
};

matrix::matrix (int rowsz, int colsz)
{
 cout << “constructing matrix object” << endl;
 if (rowsz <=0 || colsz <=0) 
 { mv = 0; return; }
 rows = rowsz;
 cols = colsz;
 mv = new float[rows*cols];
}

matrix::matrix (matrix& a)
{
 cout << “copying matrix object” << endl;
 rows = a.rows; cols = a.cols;
 int size = rows*cols;
 mv = new float[size];
 for (register int i=0 ; i<size ; i++)
 mv[i] = a.mv[i];
}

matrix::~matrix ()
{
 cout << “deleting matrix object” << endl;
 delete mv;
}

float&
matrix::operator() (int i, int j) 
{ 
 if (i<0 || i>= rows) 
 error(“class matrix: column index out of range”);
 if (j<0 || j>= cols) 
 error(“class matrix: row index out of range”);
 return mv[i*cols + j]; 
}

matrix&
matrix::operator= (matrix& a)
{
 if ((a.rows != rows) || (a.cols != cols))
 error(“class matrix: size mismatch in assignment”);
 for (register int i=0 ; i<rows*cols ; i++)
 mv[i] = a.mv[i];
 return a;
}

matrix&
matrix::operator+ (matrix& a)
{
 if ((rows != a.rows) || (cols != a.cols))
 error(“class matrix: size mismatch in +”);
 matrix& c = *new matrix(rows,cols);
 for (register int i=0 ; i<rows*cols ; i++)
 c.mv[i] = mv[i]+a.mv[i];
 return c;
}

matrix&
matrix::operator- (matrix& a)
{
 if ((rows != a.rows) || (cols != a.cols))
 error(“class matrix: size mismatch in +”);
 matrix& c = *new matrix(rows,cols);
 for (register int i=0 ; i<rows*cols ; i++)
 c.mv[i] = mv[i]-a.mv[i];
 return c;
}

matrix&
matrix::operator* (matrix& a)
{
 if (cols != a.rows)
 error(“class matrix: size mismatch in *”);
 matrix& c = *new matrix(rows,a.cols);
 for (register int i=0 ; i<rows; i++)
 for (register int j=0 ; j<a.cols; j++)
 {
 register float sum = 0;
 for (register int k=0 ; k<cols; k++)
 sum = sum + elem(i,k)*a.elem(k,j); // elem is faster
 c(i,j) = sum;
 }
 return c;
}

vector&
matrix::operator* (vector& a)
{
 if (cols != a.sz)
 error(“class matrix: size mismatch in *vector”);
 vector& c = *new vector(rows);
 for (register int i=0 ; i<rows; i++)
 {
 register float sum = 0;
 for (register int j=0 ; j<cols; j++)
 sum = sum + elem(i,j)*a.v[j]; 
 c[i] = sum;
 }
 return c;
}

void
matrix::print()
{
 for (int i=0; i<rows; i++)
 {
 for (int j=0; j<cols-1; j++)
 cout << elem(i,j) << “ | “;
 cout << elem(i,cols-1) << endl;
 }
}

int
main(int argc, char* argv[])
{
 cout << “Start main program...” << endl;
 
 int i,j;

 cout << “Defining A and C” << endl; 
 matrix a(3,5);
 matrix c(5,3);
 
 for (i=0; i<3; i++)
 for(j=0; j<5; j++)
 {
 a(i,j) = i + (1.0*j)/10;
 c(j,i) = a(i,j) - 2;
 }

 cout << “Assigning B” << endl;  
 matrix b = a;
 
 cout << “Elements of A:” << endl;
 a.print(); 
 
 cout << “Elements of B:” << endl;
 b.print();
 
 cout << “Elements of C:” << endl;
 c.print();
 
// cout << “Defining X” << endl; 
// matrix x(3,3);
 
 cout << “Multiplying A*C into X” << endl;   
 matrix& x = a*c;
 
 cout << “Elements of A*C:” << endl;
 x.print();
 
 cout << “Defining D” << endl;
 vector d(3);
 for (i=0; i<3; i++)
 d[i] = i*2.75;

 cout << “Defining E” << endl;
 vector e = d;
 
 cout << “Multiplying C*E into F” << endl;   
 vector& f = c*e;
 
 cout << “Elements of D, E, F:” << endl;
 d.print(); e.print(); f.print(); 
 
 a(1,4) = 432.056;
 b = a;
 
 a.print(); b.print();

 delete &x; delete &f;  
 
 cout << “Exiting” << endl;
 return 0;
}

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Ember 1.8.3 - Versatile digital scrapboo...
Ember (formerly LittleSnapper) is your digital scrapbook of things that inspire you: websites, photos, apps or other things. Just drag in images that you want to keep, organize them into relevant... Read more
Apple iTunes 12.1 - Manage your music, m...
Apple iTunes lets you organize and play digital music and video on your computer. It can automatically download new music, app, and book purchases across all your devices and computers. And it's a... Read more
LibreOffice 4.4.3 - Free, open-source of...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
FoldersSynchronizer 4.2.1 - Synchronize...
FoldersSynchronizer is a popular and useful utility that synchronizes and backs-up files, folders, disks and boot disks. On each session you can apply special options like Timers, Multiple Folders,... Read more
Simon 4.0.2 - Monitor changes and crashe...
Simon monitors websites and alerts you of crashes and changes. Select pages to monitor, choose your alert options, and customize your settings. Simon does the rest. Keep a watchful eye on your... Read more
Cocktail 8.1.2 - General maintenance and...
Cocktail is a general purpose utility for OS X that lets you clean, repair and optimize your Mac. It is a powerful digital toolset that helps hundreds of thousands of Mac users around the world get... Read more
Cyberduck 4.6.4 - FTP and SFTP browser....
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
Herald 5.0.2 - Notification plugin for M...
Note: Versions 2.1.3 (for OS X 10.7), 3.0.6 (for OS X 10.8), and 4.0.8 (for OS X 10.9) are no longer supported by the developer. Herald is a notification plugin for Mail.app, Apple's Mac OS X email... Read more
DEVONthink Pro 2.8.3 - Knowledge base, i...
Save 10% with our exclusive coupon code: MACUPDATE10 DEVONthink Pro is your essential assistant for today's world, where almost everything is digital. From shopping receipts to important research... Read more
Boom 2 1.0.1 - System-wide pro audio app...
Boom 2 is a system-wide volume booster and equalizer app that is designed especially for OS X 10.10 Yosemite. It comes with a smart interface, self-calibrates itself according to your Mac, offers... Read more

Playworld Superheroes Review
Playworld Superheroes Review By Tre Lawrence on January 30th, 2015 Our Rating: :: HERO CRAFTINGUniversal App - Designed for iPhone and iPad It’s all about the imagination, fighting bad creatures — and looking good while doing so.   | Read more »
Join the SpongeBob Bubble Party in this...
Join the SpongeBob Bubble Party in this New Match 3 Bubble Poppin’ Frenzy Posted by Jessica Fisher on January 30th, 2015 [ permalink ] | Read more »
Handpick Review
Handpick Review By Jennifer Allen on January 30th, 2015 Our Rating: :: TANTALIZING SUGGESTIONSiPhone App - Designed for the iPhone, compatible with the iPad Handpick will make you hungry, as well as inspire you to cook something... | Read more »
Storm the Halls of Echo Base in First St...
Storm the Halls of Echo Base in First Star Wars: Galactic Defense Event Posted by Jessica Fisher on January 30th, 2015 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Contradiction Review
Contradiction Review By Tre Lawrence on January 30th, 2015 Our Rating: :: SPOT THE LIEiPad Only App - Designed for the iPad Contradiction is a live action point and click adventure that’s pretty engaging.   Developer: Tim Follin... | Read more »
Unlock Sunshine Girl in Ironkill with th...
Unlock Sunshine Girl in Ironkill with this special 148Apps code Posted by Rob Rich on January 29th, 2015 [ permalink ] Robo-fighter Ironkill has been out on iOS a | Read more »
Crossroad Zombies Review
Crossroad Zombies Review By Jordan Minor on January 29th, 2015 Our Rating: :: CROSSWALKING DEADiPad Only App - Designed for the iPad Crossroad Zombies is a rough draft of a cool genre mash-up.   | Read more »
Blood Brothers 2 – Tips, Cheats, and Str...
War is hell: Is it the kind of hell you want to check out? Read our Blood Brothers 2 review to find out! Blood Brothers 2, DeNA’s follow-up to the original Blood Brothers, is an intriguing card collecting / role-playing / strategy hybrid. There’s... | Read more »
Blood Brothers 2 Review
Blood Brothers 2 Review By Nadia Oxford on January 29th, 2015 Our Rating: :: AN AGGRAVATING RELATIVEUniversal App - Designed for iPhone and iPad Blood Brothers 2 is built on a simple, solid foundation, but its free-to-play system... | Read more »
I AM BREAD, the Toast of the Town, is Ro...
Have you ever dreamt of being deliciously gluten-y? Do you feel passionate about Rye and Wheat? The guys at Bossa Studios do and that is why they are bringing I AM BREAD to iOS soon. The loafy app will feature all the new content that is being... | Read more »

Price Scanner via MacPrices.net

Intel Aims to Transform Workplace With 5th-Ge...
Intel Corporation today announced the availability of its 5th generation Intel Core vPro processor family that provides cutting-edge features to enable a new and rapidly shifting workplace. To meet... Read more
iOS App Sharalike Introduces New Instant Smar...
Sharalike slideshow and photo management software for iOS, is making it easier than ever to create shareable meaningful moments with its new instant SmartShow technology. Staying organized is a goal... Read more
Apple Becomes World’s Largest Smartphone Vend...
According to the latest research data from Strategy Analytics, as global smartphone shipments grew 31 percent annually to reach a record 380 million units in the fourth quarter of 2014. Apple became... Read more
Cut the Cord: OtterBox Resurgence Power Case...
Dead batteries and broken phones are two of the biggest issues for smartphone users today. Otterbox addresses both with the new Resurgence Power Case for Apple iPhone 6, promising to make those panic... Read more
13-inch Retina MacBook Pros on sale for up to...
B&H Photo has 13″ Retina MacBook Pros on sale for $200 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.6GHz/128GB Retina MacBook Pro: $1199.99 save $100 - 13″ 2.6GHz/... Read more
15-inch 2.5GHz Retina MacBook Pro on sale for...
 B&H Photo has the 15″ 2.5GHz Retina MacBook Pro on sale for $2319.99 including free shipping plus NY sales tax only. Their price is $180 off MSRP, and it’s the lowest price available for this... Read more
Back in stock: Refurbished iPod nanos for $99...
The Apple Store has Apple Certified Refurbished 16GB iPod nanos available for $99 including free shipping and Apple’s standard one-year warranty. That’s $50 off the cost of new nanos. Most colors are... Read more
Apple lowers price on refurbished 256GB MacBo...
The Apple Store has lowered prices on Apple Certified Refurbished 2014 MacBook Airs with 256GB SSDs, now available for up to $200 off the cost of new models. An Apple one-year warranty is included... Read more
New Good Management Suite Simplifies Enterpri...
Good Technology has announced the availability of the Good Management Suite, a comprehensive cross-platform solution for organizations getting started with mobile business initiatives. Built on the... Read more
15-inch 2.0GHz Retina MacBook Pro (refurbishe...
The Apple Store has Apple Certified Refurbished previous-generation 15″ 2.0GHz Retina MacBook Pros available for $1489 including free shipping plus Apple’s standard one-year warranty. Their price is... Read more

Jobs Board

*Apple* Solutions Consultant- Retail Sales (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Event Director, *Apple* Retail Marketing -...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global engagement strategy and team. Delivering an overarching brand Read more
At-Home Chat Specialist- *Apple* Online Stor...
**Job Summary** At Apple , we believe in hard work, a fun environment, and the kind of creativity and innovation that only comes about when talented people from diverse Read more
SW QA Engineer - *Apple* TV - Apple (United...
**Job Summary** The Apple TV team is looking for experienced Quality Assurance Engineers with a passion for delivering first in class home entertainment solutions. **Key Read more
*Apple* Retail - Multiple Positions(US) - Ap...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you re also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.