|
Greg Utas wrote: Global constants, yes.
Global variables, no.
Ah, great point! +5 points for the Globals.
|
|
|
|
|
Global variables being defined by you... still might be ok.
Every variable being global in the whole file / "class" where they are defined without you making it on purpose... is looking for problems.
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
modified 26-Jun-20 19:55pm.
|
|
|
|
|
Nelek wrote: Global variables being defined by you...still might be ok. Am I really that much of a paragon?
|
|
|
|
|
It might be useful to avoid "out" parameters or overcomplicating things
I think it is like "goto" using it with moderation can be helpful and a still a "good" approach, use it without care and you will shoot in your foot or somewhere worse.
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
|
|
|
|
|
Some people consider singletons a type of global variable, but I have no qualms about using them freely. Only having one of something sometimes makes sense and doesn't mean that encapsulation has to be violated.
|
|
|
|
|
Global vars matter.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
AAAaahhhh!!!
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|
|
Ever the lighter-of-bonfires, John .
Software Zen: delete this;
|
|
|
|
|
My job is to color outside the lines.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
|
|
|
Shouldn't that be:
var a='matter', b='matter', c='matter';
|
|
|
|
|
Perfect!
#SupportHeForShe
Government can give you nothing but what it takes from somebody else. A government big enough to give you everything you want is big enough to take everything you've got, including your freedom.-Ezra Taft Benson
You must accept 1 of 2 basic premises: Either we are alone in the universe or we are not alone. Either way, the implications are staggering!-Wernher von Braun
|
|
|
|
|
Globals are a tool. Sometimes that tool comes in handy. I like globals a lot more than I like Singletons, especially if globals are wrapped in a class so they aren't scattered everywhere. Singletons, on the other hand, gnnhhhh!
(I've never felt that the verbiage to use Singletons was any better than just making sure you only implement a class once in the codebase. But if I found a place where a Singleton absolutely made sense, I'd use a Singleton.)
|
|
|
|
|
David O'Neil wrote: But if I found a place where a Singleton absolutely made sense, I'd use a Singleton I use it to keep a single instance of a logger that is used all over the application. The logger uses a blocking collection and so all other places can send stuff to the logger, the collection takes care of the entries and the logger just writes down in FIFO mode.
Would that be something making sense to you? (Just curious, I am not saying is absolutely making sense or correct, but I found the approach not that bad)
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
|
|
|
|
|
Viewing it from your perspective, it makes sense. Personally, I'd just create one instance of the logger in a global and use that everywhere. I know there is only one global, and everything in that global only has one instantiation, so I never worry about it beyond that point. I'd just make certain to place the logger at the top of the declarations in the global, so it can be used by any of the following items.
The reason I settled on the global approach is linked to my Pimple article. It just makes things easier for me. It might not make your workflows easier. I don't know, and I'm not going to be all evangelical about my methods. If it works, it works. The goal is software the user can use. Not to avoid singletons or gotos or globals.
For instance, here's the current global header for my main MIDI project at this point:
#pragma once
class Globals {
private:
uchar lastNoteVelC;
MUSIC_TIME lastNoteLenC;
MUSIC_TIME snapValueC;
public:
Globals();
~Globals();
void saveAppDefaults();
enum NoteDurations { wholeNote=3072, halfNote=1536, quarterNote=768, eigthNote=384,
sixteenthNote=192, thirtySecondNote=96, sixtyFourthNote=48, tick=1 }
noteButtonDurationC;
int noteButtonDuration() { return noteButtonDurationC; }
uchar lastNoteVel() { return lastNoteVelC; }
void lastNoteVel(uchar vel) { lastNoteVelC = vel; }
MUSIC_TIME lastNoteLen() { return lastNoteLenC; }
void lastNoteLen(MUSIC_TIME newLen) { lastNoteLenC = newLen; }
MUSIC_TIME snapValue() { return snapValueC; }
void snapValue(MUSIC_TIME val) { snapValueC = val; }
private:
std::unique_ptr<app::ControllerNames> controllersC;
public:
app::ControllerNames & controllerNames() { return *controllersC.get(); }
private:
std::unique_ptr<app::NoteValMap> noteValMapC;
public:
app::NoteValMap & noteValMap() { return *noteValMapC.get(); }
private:
std::unique_ptr<midi::KeySignatures> keySignaturesC;
public:
midi::KeySignatures & keySignatures() { return *keySignaturesC.get(); }
private:
bool useSyncLogicC;
public:
void useSyncLogic(bool state) { useSyncLogicC = state; }
inline bool useSyncLogic() { return useSyncLogicC; }
private:
bool playPriorEventsC;
public:
bool playPriorEvents() { return playPriorEventsC; }
void playPriorEvents(bool state) { playPriorEventsC = state; }
private:
double ticksPerPixelC;
int keyHeightC;
public:
inline double ticksPerPixel() { return ticksPerPixelC; }
inline void ticksPerPixel(double val) { ticksPerPixelC = val; }
int keyHeight() { return keyHeightC; }
void keyHeight(int height) { keyHeightC = height; }
public:
enum DisplayVal { DisplayTicks, DisplayTimes };
private:
DisplayVal displayValC;
public:
DisplayVal displayVal() { return displayValC; }
void displayVal(DisplayVal val) { displayValC = val; }
private:
int stopSleepTimeC;
public:
int stopSleepTime() { return stopSleepTimeC; }
private:
bool showHelpOnStartupC;
public:
bool showHelpOnStartup() { return showHelpOnStartupC; }
void showHelpOnStartup(bool state) { showHelpOnStartupC = state; }
public:
enum StopMethod { PlayNotesOff, PlayOmniModeOff, PlayOmniModeOn, PlayMonoModeOn,
PlayPolyModeOn, PlayNothing };
private:
StopMethod stopMethodC;
public:
StopMethod stopMethod() { return stopMethodC; }
void stopMethod(StopMethod newMethod) { stopMethodC = newMethod; }
private:
int pianoViewBottomNoteC;
public:
int pianoViewBottomNote() { return pianoViewBottomNoteC; }
void pianoViewBottomNote(int x) { pianoViewBottomNoteC = x; }
private:
std::unique_ptr<ui::UIManager> uiManagerC;
public:
ui::UIManager & uiMan() { return *uiManagerC.get(); }
private:
std::unique_ptr<medit::Strings> stringsC;
public:
medit::Strings & strings() { return *stringsC.get(); }
public:
wString appWorkDir();
private:
int buttonHeightC = 25;
public:
int buttonHeight() { return buttonHeightC; }
private:
std::unique_ptr<utils::DateVersioner> dateVersionerC;
public:
utils::DateVersioner * dateVersioner() { return dateVersionerC.get(); }
public:
bool breakPointTrigger;
private:
int minTicksBetweenCurveEventsC;
public:
int minTicksBetweenCurveEvents() { return minTicksBetweenCurveEventsC; }
};
It is simple, and I control the instantiation order of everything in it. Some of it is rarely used in the rest of the codebase, but the UIManager it extensively accessed from almost everywhere for all the color choices and everything else related to UI. Knowing that things are there, my life as a programmer is easier.
As per gotos, I only have a few in my work. Here's one location that seems to be a good choice, from my perspective. It is the way my brain thinks of the solution. I know they could be eliminated, but I believe it would take several more lines of code to do so, and I have better things to worry about than whether the code is 'goto'-free:
void Repeat::createRepeatedMsgs() {
if (!createdMsgsC.empty()) throw dwl::Exception(_T("Delete created msgs prior to "
"creation"));
app::MsgPlayMap & holder = trackC.playMap();
holder.setPtrPos(s_cast<MUSIC_TIME>(0));
midi::BaseMsg * msg;
midi::BaseMsg * msgToCopy;
while ((msg = holder.msgAtPtr()) && msg != nullptr && msg->tick() < endTickC) {
if (msg->tick() < tickC) goto breakout;
for (size_t i=1, count=numRepeatsC; i<=count; ++i) {
midi::BaseMsg::Type type = msg->type();
if (type == midi::BaseMsg::Type::NoteOn) {
midi::NoteOn * noteOn = s_cast<midi::NoteOn *>(msg);
midi::Note * note = s_cast<midi::Note*>(noteOn->parent());
if (note) msgToCopy = note;
else msgToCopy = noteOn;
}
else if (type == midi::BaseMsg::Type::NoteOff) goto breakout;
else if (type == midi::BaseMsg::Type::KeyAftertouch) goto breakout;
else msgToCopy = msg;
if (msgToCopy->copyOf()) goto breakout;
std::unique_ptr<midi::BaseMsg> newMsg = msgToCopy->copyToTick(msgToCopy->tick() +
durationC * i);
if (newMsg->type() == midi::BaseMsg::Type::Note) {
s_cast<midi::Note*>(newMsg.get())->noteOn().copyOf((midi::BaseMsg*)1);
s_cast<midi::Note*>(newMsg.get())->noteOff().copyOf((midi::BaseMsg*)1);
}
createdMsgsC.push_back(newMsg.get());
newMsg.release(); }
breakout:
holder.incMsgPtr();
}
for (auto msg: createdMsgsC) {
msg->addToVisible();
}
}
|
|
|
|
|
I like singletons. I don't force it on the programmer though. My apps usually singletons for the DAL, connection string, and app configuration settings, and in my objects that use the singletons, I add properties that ease the typing you need to do to access the singleton objects. I also have a static Globals object.
Arguments against either singletons and globals are pointless, because a decent programmer knows when and how to use either one.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
#realJSOP wrote: app configuration settings
#realJSOP wrote: I also have a static Globals object
These really make sense and are actually thought out. The real issue with globals is that newer devs may create single global variables all over the place and then you just have this pile of stuff that cannot be managed. That's the real problem I'm talking about. And namespace crashes -- oops someone used that var name somewhere else and I didn't know it and now I've just clobbered their value and they've clobbered mine.
|
|
|
|
|
My reply is encapsulated in my reply to Nelek, up above. In short, if it works for you, it works. That's all that matters.
|
|
|
|
|
I use singletons freely, especially as flyweights[^]. But there are also other uses, such as threads that each perform a specific function.
|
|
|
|
|
Wow, flyweight. You don't hear much about that pattern being used. I've implemented it once but then it didn't get used in prod anyways.
|
|
|
|
|
David O'Neil wrote: Globals are a tool.
I agree with that. I just think that in Python they made globals to default like that to make it easier for people learning to program. However, I don't think it makes it easier really. It is confusing in a different way really.
David O'Neil wrote: But if I found a place where a Singleton absolutely made sense, I'd use a Singleton
That's good balance. Also, I like a Singleton for app configuration. There really is only one app config but there it is also a good candidate because it is made up of multiple properties which probably means having them all together in one object is nice instead of spread around in the code where you have to look everywhere to find them.
|
|
|
|
|
The Python code you posted looks ugly. I agree with your assessment. My reply to your other point is encapsulated in my reply to Nelek, up above. If it works for you, though, it works. And that's all that really matters.
|
|
|
|
|
David O'Neil wrote: If it works for you, though, it works. And that's all that really matters.
Yeah, I agree to a point. I'm working on some old prod code right now that is written in Java.
Because the original dev didn't understand anything he created every variable as a global.
The code is 2500 lines or so and it does some important prod work that is very simple --- or could be simple if the code wasn't so terrible.
Now you can't tell if you can change the variable you are looking at in the method way down on line 1000 because it may be used somewhere else and you can't tell if your change will kill it.
Side Effects
These are side effects. And they are really bad. The new paradigm of Functional Programming has a main point of attempting to remove all side effects because they are so difficult to manage. In Functional Programming, no function should ever create a side effect. Globals do the exact opposite.
Also, my main point about Python is the way that everything you declare and use automatically gets placed in the global namespace. That will always seem crazy to me.
|
|
|
|
|