Recycling, Not All It’s Cracked Up to Be

I was looking at my shampoo bottle today and noted that it said on the side of the container that the bottle was made from 100% recycled waste. I applaud the vendor, Paul Mitchell, for taking this step. The associated cream rinse also comes in a 100% recycled bottle. These are the only two bottles on any of my shelves that make this claim, which makes me wonder why other vendors aren’t going the same route (or at least telling me about it).

Just where do all of those plastic bottles sent off for recycling go anyway? According to Only about 5% of plastic waste gets recycled in US, new report says, they apparently go into the landfill, which is disappointing. The reason is simple according to Recycling plastic is practically impossible — and the problem is getting worse. It all comes down to money—making new bottles is cheaper. Still, at least one vendor is using recycled bottles, which makes me wonder why it’s possible for them and no one else. At least Recycling in the U.S. Is Broken. How Do We Fix It? is asking the right questions, but now we need answers.

One of the answers that corporations have come up with for the plastic problem is more horrible than the problem itself. According to This “Climate-Friendly” Fuel Comes With an Astronomical Cancer Risk, the EPA recently greenlighted the use of plastics for fuel. The process used to perform this conversion produces so much air pollution that it’s expected that one in four people exposed to it will develop cancer. Pyrolysis (originally meant for biomass conversion, not plastics), the process used to perform the conversion, is at the center of the pollution problem.

There are other, safer, methods than pyrolysis such as hydrothermal upgrading (HTU) available, as described in Purdue innovation affordably turning plastics into fuel. According to Hydrothermal Upgrading Of Waste Plastics: An Environmental Impact Study (see Figure 2), HTU is more environmentally friendly than pyrolysis (both of which are better for the environment than incineration). Still, there has to be a better way of recycling plastics than anything available today (with a nod to HTU being the preferred method).

The bottom line is that plastic represents a major source of pollution and further steps are required to reduce it. Unfortunately, nothing I can find online tells me that there are currently any good solutions and nothing even in the works. I’d love to hear that there is some magic solution that I haven’t found yet because it’s discouraging to think that we’ll soon be wading waist deep in plastic waste.

There are simple things that every person can do to reduce plastic pollution:

  • Asking for paper bags when going to the store unless the bags will be used for other purposes.
  • Buying milk and other dairy in glass jars that are then brought back to the store for reuse.
  • Using reusable containers for drinks and not asking for plastic straws also helps.
  • Relying on metal or other containers that are more easily recycled at a higher rate that plastic.
  • Looking for ways of separating plastics for recycling when possible (which makes it easier for recycling companies to reuse it).
  • Cleaning your plastics before recycling them.
  • Ensuring recyclables end up in the appropriate recycle bin, rather than in the trash.

In fact, it doesn’t take much thought at all to greatly reduce the amount of plastic used in the average home and the benefits are obvious when you consider a one in four cancer rate for some of the alternatives. Let me know your thoughts about plastic recycling at [email protected].

Creating Sensible Error Trapping

This is an update of a post that originally appeared on May 23, 2011.

Errors in software happen. A file is missing on the hard drive or the user presses an unexpected key combination. There are errors of all shapes and sizes; expected and unexpected. The sources of errors are almost limitless. Some developers look at this vastness, become overwhelmed, and handle all errors the same way—by generating an ambiguous exception for absolutely every error that doesn’t help anyone solve anything. This is the worst case scenario that’s all too common in software today. I’ve talked with any number of people who have had to employ extreme effort just to figure the source of the exception out; many people simply give up and hope that someone has already discovered the source of the error.

At one time, error handling functionality in application development languages was so poor that it was possible to give the developer the benefit of a doubt. However, with the development tools that developers have at their disposal today, there is never a reason to provide an ambiguous “one size fits all” exception. For one thing, developers should make a distinction between the expected and the unexpected. Any expected error—a missing file for example—should be handled directly and specifically. If the application absolutely must have the file and can’t recreate it, then it should display a message saying which file is missing, where it is missing from, and possibly how to obtain another copy.

Even more than simply shoving the burden onto the user, however, modern applications have significantly more resources available for handling the error automatically. For example, it’s quite possible to use an Internet connection to access the vendor’s Web site and automatically download a missing application file. Except to tell the user what’s happening when the repair will take a few minutes, the application shouldn’t even bother the user with this particular kind of error—the repair should be automatic.

All of my essential programming books include at least mentions of error handling, debugging, exceptions, and other tasks associated with running code efficiently and smoothly. For example, Part IV of C++ All-In-One for Dummies, 4th Edition is devoted to the topic of debugging. Part V Chapter 3 of this same book talks about exceptions. If you’re a C# developer, C# 10.0 All-in-One for Dummies discusses exception handling in Book I Chapter 9. Book IV Chapter 2 discusses how to use the debugger to find errors. The point is that it’s essential to handle errors in your applications in a manner that makes sense to the users who rely on the application daily and the developers who maintain it.

Note that many of my newer books provide instructions for working with online IDEs, most especially Google Colab. These online IDEs rarely provide built-in debugging functionality, so then you need to resort to other means, such as those expressed in Debugging in Google Colab notebook.

Exceptional conditions do occur. However, even in these situations the developer must avoid the generic exception at all costs. If an application experiences an unexpected error and there isn’t any way to recover from it automatically, the user requires as much information as possible about the error in order to fix it. This means that the application should diagnose the problem as much as possible. Don’t tell the user that the application simply has to end—there is never a good reason to include this sort of message. Instead, tell the user that the application can’t locate a required resource and specify the resource in as much detail as possible. If possible, let the user fix the resource access problem and then retry access before you simply let the application die an ignoble death. Remember this! Any exception that your application displays means that you’ve failed as a developer to locate and repair the errors, so exceptions should be reserved for truly exceptional conditions.

Not everyone agrees with my approach to error trapping, but I have yet to hear a convincing argument to provide unreliable, non-specific error trapping in an application. Poor error trapping always translates into increased user dissatisfaction, increased support costs, and a reduction in profitability. Let me know your thoughts on the issue of creating a sensible error trapping strategy at [email protected].

An Update on the RunAs Command


This is an update of a post that originally appeared on 
May 14, 2014.

Recently I wrote the Simulating Users with the RunAs Command post that describes how to use the RunAs command to perform tasks that the user’s account can’t normally perform. (The basics of using the RunAs command appear in Windows Command-Line Administration Instant Reference.) A number of you have written to tell me that there is a problem with using the RunAs command with built-in commands—those that appear as part of CMD.EXE. For example, when you try the following command:

RunAs /User:Administrator "md \Temp"

you are asked for the Administrator password as normal. After you supply the password, you get two error messages:

RUNAS ERROR: Unable to run - md \Temp
2: The system cannot find the file specified.

In fact, you find that built-in commands as a whole won’t work as anticipated. One way to overcome this problem is to place the commands in a batch file and then run the batch file as an administrator. This solution works fine when you plan to execute the command regularly. However, it’s not optimal when you plan to execute the command just once or twice. In this case, you must execute a copy of the command processor and use it to execute the command as shown here:

RunAs /User:Administrator "cmd /c \"md \Temp""

This command looks pretty convoluted, but it’s straightforward if you take it apart a little at a time. At the heart of everything is the md \Temp part of the command. In order to make this a separate command, you must enclose it in double quotes. Remember to escape the double quote that appears within the command string by using a backslash (as in \").

To execute the command processor, you simply type cmd. However, you want the command processor to start, execute the command, and then terminate, so you also add the /c command line switch. The command processor string is also enclosed within double quotes to make it appear as a single command to RunAs.

Make sure you use forward slashes and backslashes as needed. Using the wrong slash will make the command fail.

The RunAs command can now proceed as you normally use it. In this case, the command only includes the username. You can also include the password, when necessary. Let me know if you find this workaround helpful at [email protected].

Accessing a Global String

This is an update of a post that originally appeared on June 30, 2011.

Some examples work well across multiple editions of my book with slight modifications, so if you have the third edition of my book and this code looks familiar, it probably is with small changes. The example in question in this case now appears in Book I Chapter 7 of C++ All-In-One for Dummies, 4th Edition. The example shown in Listings 7-6, 7-7, and 7-8 describes how to declare a global int variable using extern and one reader wanted to extend this example to the string type. The reader had tried several times, but kept getting the following error message (in fact, you can find this same error in Code::Blocks 8.02 and 10.05 and the update in this post works with both versions):

error: 'string' does not name a type

I’m assuming that you’ve already read the discussion about this example (be sure you read the entire section from pages 183 to 185). Creating a fix for this problem isn’t hard, but providing some example code will make things easier to understand. The first issue is to include the required support in main.cpp (shown in Listing 7-6). Here’s an updated version that includes an entry for a string variable named CheeseburgerType.

#include <iostream>
#include <string>
#include "sharealike.h"
 
using namespace std;
 
int main()
{
  DoubleCheeseburgers = 20;
  CheeseburgerType = "Deluxe";
  EatAtJoes();
  return 0;
}

As you can see, you must provide #include <string> and then set CheeseburgerType to a value, which is "Deluxe" in this case. Otherwise, the example works precisely the same as before.

Let’s look at sharealike.h next (Listing 7-7). The following code changes are essential or the example will never work.

#ifndef SHAREALIKE_H_INCLUDED
#define SHAREALIKE_H_INCLUDED
 
using namespace std;
 
extern int DoubleCheeseburgers;
extern string CheeseburgerType;
void EatAtJoes();
 
#endif // SHAREALIKE_H_INCLUDED

Notice the inclusion of using namespace std;. The example will fail to compile without this statement added unless you specify the namespace as part of the type declaration. Once you define this addition, you can create the extern string CheeseburgerType; declaration. Of course, if string were part of another namespace, you’d use that namespace instead.

The final part of the puzzle is to create the required implementation. This part appears in sharealike.cpp (Listing 7-8). Here’s the final piece of the example:

#include <iostream>
#include <string>
#include "sharealike.h"
 
using namespace std;
 
int DoubleCheeseburgers;
string CheeseburgerType;
 
void EatAtJoes() {
  cout << "How many cheeseburgers today?" << endl;
  cout << DoubleCheeseburgers << " " << CheeseburgerType << endl;
 }

As with main.cpp, you must add the appropriate #include. In addition, this part of the example updates EatAtJoes() to include CheeseburgerType in the output. When you run this example, you’ll now see a cheeseburger type in the output as shown here:

The output of the updated version of GlobalVariable shows the kind of cheeseburger.
The output of GlobalVariable now shows the kind of cheeseburger.

Are there any questions on this extension? Please let me know at [email protected]. You can download the updated version of the code as GlobalVariable2 here:

Locating the Machine Learning for Dummies, 2nd Edition Source Code

A reader recently wrote to say that the source code for Machine Learning for Dummies, 2nd Edition on GitHub is incomplete. Actually, that wasn’t originally one of the download sources for the book’s code and we had used that site for an intermediary code location, so it wasn’t complete. The GitHub site code is complete now, but we’d still prefer that you download the code from one of the two sites listed in the book: On my website at http://www.johnmuellerbooks.com/source-code/ (just click the book’s link) or from the Wiley site at https://www.wiley.com/en-us/Machine+Learning+For+Dummies%2C+2nd+Edition-p-9781119724056 (just click the Downloads link, then the download link next to the source code you want). The two preferred sites offer the source code in either Python or R form in case you don’t want to download both.

When you get the downloadable source, make sure you remove it from the archive as described in the UnZIPping the Downloadable Source post. Using the downloadable source helps you avoid some of the issues described in the Verifying Your Hand Typed Code post. Please let me know whenever you encounter problems with the downloadable source for a book at [email protected].

Simulating Users with the RunAs Command

This is an update of a post that originally appeared on April 26, 2011.

One of the problems with writing applications, administering any network, or understanding system issues is to ensure that you see things from the user’s perspective. It doesn’t matter what your forte might be (programmer, administrator, DBA, manager, or the like), getting the user view of things is essential or your efforts are doomed to failure. Of course, this means seeing what the user sees. Anyone can run an application at the administrator level with good success, but the user level is another story because the user might not have access to resources or rights to perform tasks correctly.

Most knowledgeable users know that you can simulate an administrator by right clicking the application and choosing Run As Administrator from the context menu. In fact, if you Shift+Right Click the application, you’ll see an entry for Run As A Different User on the context menu that allows you to start the application as any user on the system. However, the GUI has limitations, including an inability to use this approach for batch testing of an application. In addition, this approach uses the RunAs command defaults, such as loading the user’s profile, which could cause the application to react differently than it does on the user’s system because it can’t find the resources it needs on your system.

A more practical approach is to use the RunAs command directly to get the job done. You can see some basic coverage of this command on page 480 of Windows Command-Line Administration Instant Reference. To gain a basic appreciation of how the user views things, simply type RunAs /User:UserName Command and press Enter (where UserName is the user’s fully qualified logon name including domain and Command is the command you wish to test). For example, if you want to see how Notepad works for user John, you’d type RunAs /User:John Notepad and press Enter. At this point, the RunAs command will ask for the user’s password. You’ll need to ask the user to enter it for you, but at that point, you can work with the application precisely as the user works with it.

Note that I highly recommend that you create test user accounts with the rights that real users have, rather than use a real user’s account for testing. Otherwise, if something goes wrong (and it usually does), you’ve damaged a real user’s account. Make sure you follow all of the usual policies to create this test user account and that you have as many test user accounts as needed to meet your organization’s needs.

Of course, many commands require that you provide command line arguments. In order to use command line arguments, you must enclose the entire command in double quotes. For example, if you want to open a file named Output.TXT located in the C:\MyDocs folder using Notepad and see it in precisely the same way that the user sees it, you’d type RunAs /User:John “Notepad C:\MyDocs\Output.TXT” and press Enter.

In some cases, you need to test the application using the users credentials, but find that the user’s profile gets in the way. The user’s system probably isn’t set up the same as your system, so you need your profile so that the system can find things on your machine and not on the user’s machine. In this case, you add the /NoProfile command line switch to use your profile. It’s a good idea to try the command with the user’s profile first, just to get things as close as you can to what the user sees. The default is to load the user’s profile, so you don’t have to do anything special to obtain this effect.

An entire group of users might experience a problem with an application. In this case, you don’t necessarily want to test with a particular user’s account, but with a specific trust level. You can see the trust levels setup on your system by typing RunAs /ShowTrustLevels and pressing Enter. To run an application using a trust level, use the /TrustLevel command line switch. For example, to open Output.TXT as a basic user, you’d type RunAs /TrustLevel:0x20000 “Notepad C:\MyDocs\Output.TXT” and press Enter. The basic trust levels are:

  • 0x40000 – System
  • 0x30000 – Administrator
  • 0x20000 – Basic User
  • 0x10000 – Untrusted User

Many people are experiencing problems using the /ShowTrustLevels and /TrustLevel command line switches with newer versions of Windows. The consensus seems to be that Microsoft has changed things with the introduction of UAC and that you’ll need to work with the new Elevation Power Toys to get the job done. You may also want to review the article PowerToys running with administrator permissions because it provides some insights that may be helpful in this case as well. I’d be interested in hearing about people’s experiences. Contact me at [email protected].

Checking Your Compiler in Code::Blocks

This is an update of a post that originally appeared on April 6, 2011.

Compilers are important because they turn your human-readable source code into executable code that the computer understands. Selecting the right compiler is essential if you want to obtain the best results from your application. Some readers have asked, “Just how do you select a compiler when working with C++ All-In-One for Dummies, 4th Edition?” The book assumes that you’re using the GNU GCC Compiler setting and there isn’t any guarantee another compiler will work with the book’s source code. Use these steps to check your compiler setting.

  1. Open the Code::Blocks application.
  2. Choose Settings | Compiler and you see the Global Compiler Settings dialog box shown here:
    A display of the Global Compiler Settings dialog box in Code::Blocks.
  3. Choose GNU GCC Compiler in the Selected Compiler field as shown in the figure.
  4. Click OK.

You should be ready to work with the book’s code at this point. Let me know if you have any problems choosing the right compiler at [email protected].

Considering the Four Levels of Intelligence Management

One of the reasons that Luca and I wrote Artificial Intelligence for Dummies, 2nd Edition was to dispel some of the myths and hype surrounding machine-based intelligence. If anything, the amount of ill-conceived and blatantly false information surrounding AI has only increased since then. So now we have articles like Microsoft’s Bing wants to unleash ‘destruction’ on the internet out there that espouse ideas that can’t work at all because AIs feel nothing. Of course, there is the other end of the spectrum in articles like David Guetta says the future of music is in AI, which also can’t work because computers aren’t creative. A third kind of article starts to bring some reality back into the picture, such as Are you a robot? Sci-fi magazine stops accepting submissions after it found more than 500 stories received from contributors were AI-generated. All of this is interesting for me to read about because I want to see how people react to a technology that I know is simply a technology and nothing more. Anthropomorphizing computers is a truly horrible idea because it leads to the thoughts described in The Risk of a New AI Winter. Another AI winter would be a loss for everyone because AI really is a great tool.

As part Python for Data Science for Dummies and Machine Learning for Dummies, 2nd Edition Luca and I considered issues like the seven kinds of intelligence and how an AI can only partially express most of them. We even talked about how the five mistruths in data can cause issues such as skewed or even false results in machine learning output. In  Machine Learning Security Principles I point out the manifest ways in which humans can use superior intelligence to easily thwart an AI. Still, people seem to refuse to believe that an AI is the product of clever human programmers, a whole lot of data, and methods of managing algorithms. Yes, it’s all about the math.

This post goes to the next step. During my readings of various texts, especially those of a psychological and medical variety, I’ve come to understand that humans embrace four levels of intelligence management. We don’t actually learn in a single step as might be thought by many people, we learn in four steps with each step providing new insights and capabilities. Consider these learning management steps:

  1. Knowledge: A person learns about a new kind of intelligence. That intelligence can affect them physically, emotionally, mentally, or some combination of the three. However, simply knowing about something doesn’t make it useful. An AI can accommodate this level (and even excel at it) because it has a dataset that is simply packed with knowledge. However, the AI only sees numbers, bits, values, and nothing more. There is no comprehension as is the case with humans. Think of knowledge as the what of intelligence.
  2. Skill: After working with new knowledge for some period of time, a human will build a skill in using that knowledge to perform tasks. In fact, very often this is the highest level that a human will achieve with a given bit of knowledge, which I think is the source of confusion for some people with regard to AIs. Training an AI model, that is, assigning weights to a neural network created of algorithms, gives an AI an appearance of skill. However, the AI isn’t actually skilled, it can’t accommodate variations as a human will. What the AI is doing is following the parameters of the algorithm used to create its model. This is the highest step that any AI can achieve. Think of skill as the how of intelligence.
  3. Understanding: As a human develops a skill and uses the skill to perform tasks regularly, new insights develop and the person begins to understand the intelligence at a deeper level, making it possible for a person to use the intelligence in new ways to perform new tasks. A computer is unable to understand anything because it lacks self-awareness, which is a requirement for understanding anything at all. Think of understanding as the why of intelligence.
  4. Wisdom: Simply understanding an intelligence is often not enough to ensure the use of that intelligence in a correct manner. When a person makes enough mistakes in using an intelligence, wisdom in its use begins to take shape. Computers have no moral or ethical ability—they lack any sort of common sense. This is why you keep seeing articles about AIs that are seemingly running amok, the AI has no concept whatsoever of what it is doing or why. All that the AI is doing is crunching numbers. Think of wisdom as the when of intelligence.

It’s critical that society begin to see AIs for what they are, exceptionally useful tools that can be used to perform certain tasks that require only knowledge and a modicum of skill and to augment a human when some level of intelligence management above these levels is required. Otherwise, we’ll eventually get engulfed in another AI winter that thwarts development of further AI capabilities that could help people do things like go to Mars, mine minerals in an environmentally friendly way in space, cure diseases, and create new thoughts that have never seen the light of day before. What are your thoughts on intelligence management? Let me know at [email protected].

Creating Useful Comments

This is an update of a post that originally appeared on November 21, 2011.

A major problem with most applications today is that they lack useful comments. It’s impossible for anyone to truly understand how an application works unless the developer provides comments at the time the code is written. In fact, this issue extends to the developer. A month after someone writes an application, it’s possible to forget the important details about it. In fact, for some of us, the interval between writing and forgetting is even shorter. Despite my best efforts and those of many other authors, many online examples lack any comments whatsoever, making them nearly useless to anyone who lacks time to run the application through a debugger to discover how it works.

Good application code comments help developers of all stripes in a number of ways. As a minimum, the comments you provide as part of your application code provides these benefits.

  • Debugging: It’s easier to debug an application that has good comments because the comments help the person performing the debugging understand how the developer envisioned the application working.
  • Updating: Anyone who has tried to update an application that lacks comments knows the pain of trying to figure out the best way to do it. Often, an update introduces new bugs because the person performing the update doesn’t understand how to interact with the original code.
  • Documentation: Modern IDEs often provide a means of automatically generating application documentation based on the developer comments. Good comments significantly reduce the work required to create documentation and sometimes eliminate it altogether.
  • Technique Description: You get a brainstorm in the middle of the night and try it in your code the next day. It works! Comments help you preserve the brainstorm that you won’t get back later no matter how hard you try. The technique you use today could also solve problems in future applications, but the technique may become unavailable unless you document it.
  • Problem Resolution: Code often takes a circuitous route to accomplish a task because the direct path will result in failure. Unless you document your reasons for using a less direct route, an update could cause problems by removing the safeguards you’ve provided.
  • Performance Tuning: Good comments help anyone tuning the application understand where performance changes could end up causing the application to run more slowly or not at all. A lot of performance improvements end up hurting the user, the data, or the application because the person tuning the application didn’t have proper comments for making the adjustments.

The need for good comments means creating a comment that has the substance required for someone to understand and use it. Unfortunately, it’s sometimes hard to determine what a good comment contains in the moment because you already know what the code does and how it does it. Consequently, having a guide as to what to write is helpful. When writing a comment, ask yourself these questions:

  • Who is affected by the code?
  • What is the code supposed to do?
  • When is the code supposed to perform this task?
  • Where does the code obtain resources needed to perform the task?
  • Why did the developer use a particular technique to write the code?
  • How does the code accomplish the task without causing problems with other applications or system resources?

There are many other questions you could ask yourself, but these six questions are a good start. You won’t answer every question for every last piece of code in the application because sometimes a question isn’t pertinent. As you work through your code and gain experience, start writing down questions you find yourself asking. Good answers to aggravating questions produce superior comments. Whenever you pull your hair out trying to figure out someone’s code, especially your own, remember that a comment could have saved you time, frustration, and effort. What is your take on comments? Let me know at [email protected].

C++ Data Type Usage

This is an update of a post that originally appeared on October 16, 2015.

Originally I provided this post to correct an example in a previous edition of the book. Now I’m providing it to clarify that same example to a greater degree and answer reader input. The Going Overboard section on page 64 of C++ All-In-One for Dummies, 4th Edition talks about the problems that can occur when you try to stuff a number that’s too large into a specific data type. The problem with the example shown:

cout << 12345678 * 100 / 2 * 3 * 3 << endl;

is that while it does display a warning message, the warning really doesn’t get the point across. In order to see the example as originally intended, you need to change the code to read:

long MyLong = 12345678 * 100 / 2 * 3 * 3;
cout << MyLong << endl;

The code will now produce a warning and you can see why in a clearer way, just as described in the book, because the data type isn’t ambiguous any longer. In both cases you see a warning message of:

warning: integer overflow in expression of type 'int' results in '1260587804'

One of the ways to overcome this problem is to ensure that you use the correct sized variable in the first place. The following code doesn’t produce a warning message because of the use of auto (telling the compiler to choose the correct variable type automatically) and ll (telling the compiler to use a long long variable for the calculation).

auto AutoSize = 12345678ll * 100 / 2 * 3 * 3;
cout << AutoSize << endl;

A number of readers were happy that I pointed the problem out, but wanted to see a fix for the problem as well. When you run the example with the additional code, you see outputs of:

1260587804
1260587804
5555555100

Only the third answer is the correct one and it points out the need to pay attention to both warnings and errors as you code. Please let me know if you have any questions or concerns about this example at [email protected].