Can't Output Array Element & How Do I "Recycle" My Prompt()


#1

In this code

var arr = [];

function toDo() {
	var userInput = prompt("What would you like to do?\n\nType:\n\"New\" to add a To-Do\n\"List\" to view the To-Do List\n\"Quit\" to exit this program");
	switch (userInput) {
		case "new":
			addToDo = arr.push(prompt("Add New To-Do:"));
			alert("New To-Do \"" + addToDo + "\" added.");
			toDo();
			break;
		case "list":
			alert("To-Do List Items:\n\n" + arr.join(", "));
			toDo();
			break;
		case "quit":
			arr = [];
			alert("Quitting!");
			break;
		default:
			userInput = prompt("Please choose \"New,\" \"List,\" or \"Quit:\"");
	}
}

toDo();

I’m unable to

1) get alert(“New To-Do “” + addToDo + “” added.”); to display the array element just entered (I’d even tried addToDo.value but that also doesn’t work)
2) have the default-case “recycle” the prompt() (I know that I can just do a “re-call” or “re-invocation” with toDo(); like in all other cases but I’m curious how it would be possible to “recycle,” as I say, the prompt())

THANK YOU!!!


#2

As stated earlier, you are making your function do too much. This is poor design.

function getUserInput(prompt, values) {
    // prompt => string
    // values => array
    // only return when user input matches a value
    // or the user cancels
}

#3

Well, that’s why I’d wondered whether switch statements were even “practical” in that other eponymous thread at Are Switch Statements Useful/Practical?

But while it’s “poor design” given the limitations of, I dunno, JS or CS in general, does it mean that 2) is impossible??

And what about 1)?

Also, I have to ask: how’s this simple thing “too much” for even just one function? It’s a switch statement after all, wrapped within the form of a function only so that I can re-loop the thing. It ain’t too much for a switch statement, is it? I mean, what with all the cases involved, which is the whole point of a switch statement in the first place…


#4

A switch is a control flow object, intended to direct traffic. It should not be the engine of the program, just the traffic cop. That’s why we have functions. Small, pure ones to do simple tasks and an outer one to give closure to the whole thing. Functions should not change state, but do the leadup work in preparation for that state change. Good program design is built around a central controller (the data) with a model that processes or handles that data in precise, succinct, discernible ways. The view is handled separately, in a controlled way, not at the whimsy of every other function.

I stand behind my earlier suggestion… Stick to basics and get some strength from that. Everything will unfold in time, as it should. Right now, in my humblest opinion, you are looking in the wrong direction. Focus on making your swtich function above into an actual program that utilizes functional programming concepts as much as possible.


#5

Makes sense – and I have wondered about their wider use beyond trivial beginners’ exercises, so I appreciate your elaboration. But why should switch not serve as an engine? I see it as a great way to organize the broad logic of a program. Why’s this bad??

But I do believe that it’s serving as a traffic cop in the code here, directing different actions based on different outcomes. That it may appear as “the engine” is only because the program is so simple, of course! So it puzzles me greatly that you don’t see it as a traffic cop here, my switch statement…why not?? Seems so obvious to me!

Well, that’s interesting…especially the “outer one to give closure to the whole thing” bit 'cause it seems like my switch here is doing just that, too! In fact, I chose switch precisely because it’s so clear and organized, unlike a messy nest of if-else-if-else statements, giving the whole program a nice frame or form…don’t you agree that it’s a nice clear hierarchical chart-like frame?

Wow, what?? Not change states??? Why not?? What does/would, then??? The data?? And how does the data, as data, change states…!!!

You mean like how CSS (presentation) is distinct from HTML (semantics) from JS (behavior)??

Okay, makes sense – but as a practical matter, doesn’t the view change based on user input, and thus “at the whimsy of every other function” that deals with user input??

But these are the basics! Computer science stuff like flow control and program design…I mean, it’s because I don’t know these basics that you’re here telling me about them, how switch should not be the engine of a program and so forth…!

I value your thoughts highly, which is why I keep asking you so much about so many things!

But I don’t even know what “functional programming” is, never mind trying to refactor my simple program along the lines of such an august-sounding paradigm…so I can’t imagine how I could make my switch statement something more “functional”…

Obviously, it’s like I’m Christopher Columbus expecting to reach China and there’s this whole Western Hemisphere thingamajig in the way so please bear with me; here are my questions:

  1. Why should switch not serve as the engine of a program?
  2. What should such an engine be, if not even functions – the data??
  3. Why would a functional programming model be good for even the humble thing I’m doing here in this code?

#6

BTW, in 1) I know I can simply do alert("New To-Do \"" + arr[arr.length - 1] + "\" added."); but for some reason my mind first conceived of addToDo = arr.push(prompt("Add New To-Do:")); – as in

var addToDo = "";
	if (userInput === "new") {
		var addToDo = "";
		addToDo = arr.push(prompt("Add New To-Do:"));
		alert("New To-Do \"" + addToDo + "\" added.");

so I’m just really curious why the logic didn’t work there:

  1. declare var addToDo = "";
  2. capture value of input with addToDo = arr.push(prompt("Add New To-Do:"));
  3. insert value of input with alert("New To-Do \"" + addToDo + "\" added.");

Please let me know what I’m “missing” in terms of my logic or overall understanding of how JavaScript works!


#7

I gave you and example of what a simple switch might look like. It directs traffic and that is it.

function action(user) {
  // returns a function reference
  switch (user) {
  case 'new': return newItem;
  case 'list': return listItems;
  case 'delete': return removeItem;
  case 'quit': return quitProgram;
  }
}
function newItem() {
  var user = input("Enter an item to add to the to do list");
  toDoList.push(item);
}
function listItems() {
  toDoList.forEach(x => console.log(x));
}
function removeItem() {
  var user = input("Enter an item to remove from the to do list");
  var index = toDoList.indexOf(user)
  toDoList.remove(index, 1);
}
function quitProgram() {
  resume = false;
}
function input(prompt, values="") {
  // already discussed criteria for this function
}
const toDoList = [];
var resume = true;
function main () {
  var user;
  while (resume) {
    user = input("Enter [new | list | quit", ['new', 'list', 'quit']);
    // invokes the function reference
    if (user !== null) action(user)() else quit();
  }
}

This could be a working program, with a tiny bit more code (input validator). Out of the gate programs are by no means finished products. First we write code that does what we want it to do, then comes the testing/debugging and finally the refinement stage. Write code that is easy to read, is not cluttered with a whole bunch of symbols and clumsy strings, and that lets us follow the logic from beginning to end. This is not something that can be taught, but must be learned. The why’s and wherefor’s emerge with practice when we have a few hundred failures under our belt and formulate our own answers to those questions.


#8

This is kinown as an IIFE (Immediately Invoked Function Expression) which is also a closure…

Closure via IIFE
(function() {
function action(user) {
  switch (user) {
  case 'new': return newItem();
  case 'list': return listItems();
  case 'remove': return removeItem();
  case 'quit': return quitProgram();
  }
}
function newItem() {
  var item = input("Enter an item to add to the to do list");
  toDoList.push(item);
}
function listItems() {
  toDoList.forEach(x => console.log(x));
}
function removeItem() {
  var item = input("Enter an item to remove from the to do list");
  var index = toDoList.indexOf(item);
  toDoList.splice(index, 1);
}
function quitProgram() {
  resume = false;
}
function input(text, values="") {
  return prompt(text);
}
function main () {
  var user;
  while (resume) {
    user = input("Enter [new | list | remove | quit", ['new', 'list', 'remove', 'quit']);
    if (user !== null) action(user)
    else quitProgram();
  }
}
const toDoList = [];
var resume = true;
return main();
})();

Paste the whole thing into the console and hit Enter. There is still no input validation, confirmation messages or pretty print but that can be arranged.

Thought that would get you. Even the above has only one pure function: action(). No state change takes place; there is no interaction; and, it takes a value for which the outcome is predictable. Pure and simple.

The rest of the functions are definitely state changers and interact with the global namespace. But that is good since the one function we’re referring to is the one with the switch in it. Switches help us abstract control flow away from the rest of the program, and that’s what this one does.

In case you’re wondering, main() is the engine for which action() is the distributor. The functions are the cylinders. input() is the carburetor and the user is the fuel.

The first effect of this closure is that even though it looks like it is in memory, once it closes, nothing exists except the code in the namespace (and not even that if you pasted it in). Everything else vanished the minute you entered ‘quit’ or hit Cancel. (Remember this event also has bindings to the Esc key.) We can’t call the main() function because it no longer exists, and even if it did, we still couldn’t call it because it is in a closure.

So an IIFE, then, is a self-destructive piece of code that vanishes once we’re done with it. If that doesn’t manage memory well, I don’t know what does. It certainly addresses the issue of memory leakage. It’s totally garbage collected.

It follows that these sort of functions run first. They can affect state by way of the window object. Even in the closure around all of its objects, no function can escape its global parent object, window. More correctly, the window object cannot escape its children. Child objects have access via the scope chain to all of the properties of window.

This variable points JS straight at the DOM where it can work its magic on the nodes of the DOM tree, only we refer to it as document.node in scrpt and only need to reference window directly when our function shadows a global variable.

This variable ranks at the top of the scope chain. When an unscoped variable is polled JavaScript looks for it up the scope chain from the function it’s in. The end of this chain is window where its properties are scanned for the variable. If it doesn’t exist there then it is undefined. This is a whole 'nother area of study if you really want to get under the hood.


#9

And that’s just what’s so confounding – my code also “directs traffic:” in this case, do this; in that case, do that!

How is my code not directing traffic?? Just 'cause it doesn’t hand off to functions – is that what you mean?

If so, why’s that a problem? Heck, the hardware’s full of “switches,” after all! :wink: Why not the software??

Thanks! I’ll be busy digesting that, too…wow, are you like a retired CS teacher or something?? How’d you learn all this stuff??? I’m serious. Really, like what, you jsut read and read??? How long you been at this, hoss??

Well, can’t argue with that! Only, I didn’t realize my code was so hard to read…switch statements seem so visually clean and organized to me!!


#10

Why haven’t I used, let?

Here’s how I think it…

var

is for scoping a variable away from parent scope. No window properties need this. They are direct properties for which their scope is predetermined, ‘global’. If one’s prof is telling the students to declare all variables using var, they are full of it. We only use var to protect variables inside a function.

let

is the way to keep variables from polluting memory in local scope. Variables declared with let inside a block cannot leak out into their parent scope.

const

refers only to values and data structures that we cannot allow reassignment. The contents of data structures are still writable.


#11

Oh! You were using that word in its technical CS sense all along! I didn’t realize…now I’ll have to revisit your earlier remarks!

Wow, okay, I’m gonna have to be chewing on this for a while…thanks! (Burp!)

“Pure function”…okay, I’m googling it now!

Yeah, wow, thanks…really. I think with this, you’ve gotten rid of me for maybe the next three days!! A lotta ground here to cover…thanks so much, Roy!! You’re a Mensch!


#12

7 posts were split to a new topic: Music chat segue