To make code more readable in a current Inform7 project that contains special doors, I decided to create kinds of doors and things that are parts of the doors to backtrack which doors to open and close.
Background: A door can only be opened if it was previously manipulated by a thing called Mobitab and then unlocked by a Securitypass. So I created a kind of a thing called DoorpanelSM with a property manipulated (usually 0) and a property activated (usually 0). My code for the manipulation and unlocking of the doors looks like the following:
NOTE: The problem was narrowed down further. Edits are all the way to the bottom!
TürpanelSM is a kind of a thing. Sicherheitsausweis can be used with TürpanelSM. TürpanelSM has a number called activated. Activated of TürpanelSM is usually 0. TürpanelSM has a number called manipulated. Manipulated of TürpanelSM is usually 0.
Unlocking a TürpanelSM with Sicherheitsausweis is an action applying to two things.
Understand "use [Sicherheitsausweis] with [a TürpanelSM]" as unlocking a TürpanelSM with Sicherheitsausweis.
Manipulating a TürpanelSM with Mobitab is an action applying to two things.
Understand "manipulate [a TürpanelSM]" as manipulating a TürpanelSM with Mobitab.
Understand "use [Mobitab] with [a TürpanelSM]" as manipulating a TürpanelSM with Mobitab.
Instead of unlocking a TürpanelSM with Sicherheitsausweis:
if TürpanelSM (called currentPanel) is part of a door and manipulated of the currentPanel is 0:
say "Securitypass not accepted. You could try to manipulate the panel...";
otherwise if TürpanelSM (called currentPanel) is a part of a door (called the parent) and activated of the currentPanel is 0:
now the parent is unlocked;
now the parent is open;
now activated of the currentPanel is 1;
otherwise if TürpanelSM (called currentPanel) is a part of a door (called the parent) and activated of the currentPanel is 1:
now the parent is closed;
now the parent is locked;
now activated of the currentPanel is 0;
otherwise if TürpanelSM (called currentPanel) is a part of a door:
Instead of manipulating a TürpanelSM with Mobitab:
if TürpanelSM (called currentPanel) is a part of a door and manipulated of the currentPanel is 0:
now manipulated of the currentPanel is 1;
say "Panel got manipulated";
otherwise if TürpanelSM (called currentPanel) is a part of a door and manipulated of the currentPanel is 1:
say "Panel was manipulated already.";
One door only works wonderful. However if I use two or more doors, the properties of the doorpanels defined appear to be global. I am certain that now activated of the currentPanel is 0; is not changing the property of the currentPanel but declares a global variable that is asked for on each of the conditions below. I am completely unable to find a way of correctly setting and getting the values of the panel I am asking for.
Small testprogram to show the problem (includes the above):
"TestsForSO" by geisterfurz007
Locker is a container.
Mobitab is in Locker.
Securitypass is in Locker.
Locker is in Hangar.
DoorpanelSM is a kind of a thing. Securitypass can be used with DoorpanelSM. DoorpanelSM has a number called activated. Activated of DoorpanelSM is usually 0. DoorpanelSM has a number called manipulated. Manipulated of DoorpanelSM is usually 0.
Unlocking a DoorpanelSM with Securitypass is an action applying to two things.
Understand "use [Securitypass] with [a DoorpanelSM]" as unlocking a DoorpanelSM with Securitypass.
Manipulating a DoorpanelSM with Mobitab is an action applying to two things.
Understand "manipulate [a DoorpanelSM]" as manipulating a DoorpanelSM with Mobitab.
Understand "use [Mobitab] with [a DoorpanelSM]" as manipulating a DoorpanelSM with Mobitab.
Instead of unlocking a DoorpanelSM with Securitypass:
if DoorpanelSM (called currentPanel) is part of a door and manipulated of the currentPanel is 0:
say "Securitypass not accepted. You could try to manipulate the panel...";
otherwise if DoorpanelSM (called currentPanel) is a part of a door (called the parent) and activated of the currentPanel is 0:
now the parent is unlocked;
now the parent is open;
now activated of the currentPanel is 1;
otherwise if DoorpanelSM (called currentPanel) is a part of a door (called the parent) and activated of the currentPanel is 1:
now the parent is closed;
now the parent is locked;
now activated of the currentPanel is 0.
Instead of manipulating a DoorpanelSM with Mobitab:
if DoorpanelSM (called currentPanel) is a part of a door and manipulated of the currentPanel is 0:
now manipulated of the currentPanel is 1;
say "Panel got manipulated";
otherwise if DoorpanelSM (called currentPanel) is a part of a door and manipulated of the currentPanel is 1:
say "Panel was manipulated already.";
The idea is to do the following:
take Securitypass
take Mobitab
use Mobitab with TPTSM1 //which is the first doorpanel; manipulates the door
use Securitypass with TPTSM1 //opens the door
go west
use Mobitab with TPTSM2 //which would be the second doorpanel (to the northwest); says that the panel is already manipulated.
And I have no clue why... Any help is much appreciated!
EDIT: Investigating further, I used the showme command and found that the variables were properly changed on the first door, and they are both correctly at 0. However it is said that the panel is already manipulated despite the manipulated value beeing 0. Maybe the problem is connected to the currentPanel thing?
More EDIT: Actually it looks like exactly that... currentPanel seems to always be TPTSM1. My understanding was that it will change accordingly each time the rule is executed for any Doorpanel. How would I change the code to accomplish that?
Even more EDIT: So as said above (as it looks) the value of currentPanel appears to be fixxed after manipulating/unlocking it. However neither showme sees this thing nor can I use it elsewhere in the code. I know this behaviour only from parameters that are known only in functions as parameter. So this confuses me even more...
You're defining "currentPanel" too late. For example here there is no link to the door panel that the player is currently manipulating:
if DoorpanelSM (called currentPanel) is part of a door ...
It picks just some panel that exists in the game, which happens to always be TPTSM1.
If you define it earlier, here:
Instead of unlocking a DoorpanelSM (called currentPanel) with Securitypass:
then it chooses the panel that is currently being unlocked. Alternatively you could use "noun" which is automatically the target of the current action.
Unrelated side notes:
Sicherheitsausweis can be used with TürpanelSM is unlikely to do what you meant it to do: it creates an adjective called "used with TürpanelSM" and does nothing else.
Conversely, using number properties to track an object state is somewhat clunky, and adjectives are commonly used instead. So you'd define DoorpanelSM can be activated, test it with if currentPanel is activated and set it with now currentPanel is activated and now currentPanel is not activated.
Related
I'm testing a sub-optimal but really simple CSS animation in Chrome on Mac. In the dev tools, I see that "recalculate style" and subsequent activities are being executed multiple times in a single frame. "Update layer tree" is being called 3 times.
I do not see this behavior in Chrome on Windows. I also do not see equivalent behavior in Firefox.
Here is the simple demo I'm using: http://s.codepen.io/lonekorean/debug/44cf0a50e321de7ec7ff4fac5d3f4514
Why am I seeing these events repeated? It seems very inefficient for Chrome to redo that work in the same frame, so I would like to understand why.
Thanks!
A similar was asked previously on Google Forums, so I've quoted the explanation given below:
The signal that we use for frame boundaries is emitted when the
compositor actually draws layers, and there are plenty of
opportunities for the compositor to bail out before actually drawing,
most common being the update being outside of view-port. So the flow
in your case is likely as this:
you invalidate styles;
the main thread requests a frame from the impl side;
the impl side begins a frame and requests a main thread frame;
the main thread performs style recalc/layout/update layer tree;
it turns out there are no invalidations within the visible area;
frame is not drawn. (the above is repeated several times, then something is actually drawn, and at this point we mark next frame
boundary in Timeline).
Comment by: Andrey Kosyakov
Source: https://groups.google.com/forum/#!topic/google-chrome-developer-tools/JaWHxD6oaXU
From what I understand, invalidating styles is the process of deciding which elements need to have their computed styles recalculated. This is done by storing meta data of the relationships between the elements in the form of Descendant Invalidation Sets.
Update:
I can replicate the same behaviour in on Chrome for Windows as you can see below:
I can't see any reason why the compositor would bail out but I'm not so familiar with the intricate details of this. It's somewhat complicated.
I'm learning about Elm from Seven More Languages in Seven Weeks. The following example confuses me:
import Keyboard
main = lift asText (foldp (\dir presses -> presses + dir.x) 0 Keyboard.arrows)
foldp is defined as:
Signal.foldp : (a -> b -> b) -> b -> Signal a -> Signal b
It appears to me that:
the initial value of the accumulator presses is only 0 on the first evaluation of main
after the first evaluation of main it seems that the initial value of presses is whatever the result of function (a -> b -> b), or (\dir presses -> presses + dir.x) in the example, was on the previous evaluation.
If this is indeed the case, then isn't this a violation of functional programming principles, since main now maintains internal state (or at least foldp does)?
How does this work when I use foldp in multiple places in my code? Does it keep multiple internal states, one for each time I use it?
The only other alternative I see is that foldp (in the example) starts counting from 0, so to say, each time it's evaluated, and somehow folds up the entire history provided by Keyboard.arrows. This seems to me to be extremely wasteful and sure to cause out-of-memory exceptions for long run times.
Am I missing something here?
How it works
Yes, foldp keeps some internal state around. Saving the entire history would be wasteful and is not done.
If you use foldp multiple times in your code, doing distinct things or having distinct input signals, then each instance will keep it's own local state. Example:
import Keyboard
plus = (foldp (\dir presses -> presses + dir.x) 0 Keyboard.arrows)
minus = (foldp (\dir presses -> presses - dir.x) 0 Keyboard.arrows)
showThem p m = flow down (map asText [p, m])
main = lift2 showThem plus minus
But if you use the resulting signal from a foldp twice, only one foldp instance will be in your compiled program, the resulting changes will just be used in two place:
import Keyboard
plus = (foldp (\dir presses -> presses + dir.x) 0 Keyboard.arrows)
showThem p m = flow down (map asText [p, m])
main = lift2 showThem plus plus
The main question
If this is indeed the case, then isn't this a violation of functional programming principles, since main now maintains internal state (or at least foldp does)?
Functional programming doesn't have some great canonical definition that everybody uses. There are many examples of functional programming languages that allow for the use of mutable state. Some of these programming languages show you that a value is mutable in the type-system (you could see Haskell's State a type as such, it really depends on your viewpoint though).
But what is mutable state? What is a mutable value? It's a value inside the program, that is mutable. That is, it can change. It can be different things at different times. Ah, but we know how Elm calls values at change over time! That's a Signal.
So really a Signal in Elm is a value that can change over time, and can therefore be seen as a variable, a mutable value, or mutable state. It's just that we manage this value very strictly by allowing only a few well-chosen manipulations on Signals. Such a Signal can be based on other Signals in your program, or come from a library or come from the outside world (think of inputs like Mouse.position). And who knows how the outside world came up with that signal! So allowing your own Signals to be based on the past value of Signals is actually ok.
Conclusion / TL;DR
You could see Signal as a safety wrapper around mutable state. We assume that signals that come from the outside world (as input to your program) are not predictable, but because we have this safety wrapper that only allows lift/sample/filter/foldp, the program you write is otherwise completely predictable. Side-effects are contained and managed, therefore I think it's still "functional programming".
You're confusing an implementation detail with a conceptual detail. Every functional programming language eventually gets translated down to assembly code, which is decidedly imperative. That doesn't mean you can't have purity at the language level.
Don't think of main as being repeatedly evaluated, returning different results every time. A Signal is conceptually an infinite list of values. main takes an infinite list of keyboard arrows as input and translates that into an infinite list of elements. Given the same list of arrows, it will always return the exact same list of elements, without side effects. At this level of abstraction, it is therefore a pure function.
Now, it so happens that we are only interested in the last element of the sequence. This allows for some optimizations in the implementation, one of which is storing the accumulated value. What's important is that the implementation is referentially transparent. From the language's point of view, you're getting the exact same answer as if you stored the entire sequence and recomputed it from scratch every time a value is added to the end. You get the same output given the same input. The only difference is storage space and execution time.
In other words, the whole idea of functional programming is not to eliminate state tracking, but to abstract it away from the purview of the programmer. Programmers get to play in the ideal world, while the compiler and runtime slave away in the sewers of mutable state to make the ideal world possible for the rest of us.
You should note that "doesnt maintain internal state" isn't really strong definition of FP. Its much more like an implementation constraint. What definition I like more is "built from pure functions". Without diving deep, in plain English it means that all functions return same output when given same input. This definition unlike previous gives you huge reasoning power and a simple way to check whether some program follows it while keeping some optimization space on current hardware.
Given reformulated restriction functional languages are free to use mutables as long as it modelled with pure functions. Answering your question, elm programs built out of pure functions so its probably a functional language. Elm uses special data structure, Signal, to model outside world interactions and internal state as well as any other functional language does.
In Qt, I have a model subclassing QAbstractItemModel - it's a tree displayed in a QTreeView.
The model supports various forms of change which all work OK. The two of relevance are:
1) Some data in a small number of related rows changes
2) A visualisation change means that the majority of rows should change their formatting - in particular they have a change of background highlighting. Their DisplayRole data does not change.
The current design deals with both of these in the same way: for every row that has any change the model emits dataChanged(start_of_row_index,end_of_row_index). I emit the signal for both parent rows that change and for any of their children that have changed.
However, this performs badly in case 2 as the model gets big: a very large number of dataChanged signals are emitted.
I have changed the code so that in case 2 the model emits dataChanged only for the (single) row that is the parent of the entire tree.
This still appears to work correctly but does not accord with my understanding of the responsibilities of the model. But I suspect I may be wrong.
Perhaps I am misunderstanding the dataChanged signal? Does it actually cause the view to update all children as well as the specified range? Or can I avoid emitting dataChanged when it is not the DisplayRole that is changing?
Edited with my progress so far
As Jan points out, I ought to emit dataChanged either for most or all of the rows in case 2.
My code originally did this by emitting dataChanged for every changed row but this is too expensive - the view takes too long to process all these signals.
A possible solution could be to aggregate the dataChanged signal for any contiguous blocks of changed rows but this will still not perform well when, for example, every other row has changed - it would still emit too many signals.
Ideally I would like to just tell the view to consider all data as potentially changed (but all indexes still valid - the layout unchanged). This does not seem to be possible with a single signal.
Because of a quirk of the QTreeView class, it is possible (though incorrect according to the spec) to emit only one dataChanged(tl,br) as long as tl != br. I had this working and it passed our testing but left me nervous.
I have settled for now on a version which traverses the tree and emits a single dataChanged(tl,br) for every parent (with tl,br spanning all the children of that parent). This conforms to the model/view protocol and for our models it typically reduces the number of signals by about a factor of 10.
It does not seem ideal however. Any other suggestions anyone?
You are expected to let your views know whenever any data gets changed. This "letting know" can happen through multiple ways; emitting dataChanged is the most common one when the structure of the indexes has not changed; others are the "serious" ones like modelReset or layoutChanged. By a coincidence, some of the Qt's views are able to pick up changes even without dataChanged on e.g. a mouseover, but you aren't supposed to rely on that. It's an implementation detail and a subject to change.
To answer the final bit of your question, yes, dataChanged must be emitted whenever any data returned from the QAIM::data() changes, even if it's "just" some other role than Qt::DisplayRole.
You're citing performance problems. What are the hard numbers -- are you actually getting any measurable slowdown, or are you just prematurely worried that this might be a problem later on? Are you aware of the fact that you can use both arguments to the dataChanged to signal a change over a big matrix of indexes?
EDIT:
A couple more things to try:
Make sure that your view does not request extra data. For example, unless you set the QTreeView's uniformRowHeights (IIRC), the view will have to execute O(n) calls for each dataChanged signal, leading to O(n^2) complexity. That's bad.
If you are really sure that there's no way around this, you might get away by combining the layoutAboutToBeChanged, updatePersistentIndexes and layoutChanged. As you are not actually changing the structure of your indexes, this might be rather cheap. However, the optimization opportunity in the previous point is still worthwhile taking.
I have two radio buttons. When clicking one of them it should disable some widgets and activate some other. What should I do for that?
e.g If I check radioButton1 then it should disable a lineEdit instantly and if I check radioButton2 it should enable the first line edit and disable lineEdit2.
All this in real time.
Without having much to go on at the moment, a general answer would be the following:
Handle the appropriate signal of your radio buttons. Using this signal you can trigger a method/loop where you set your widgets to be disabled using setEnabled(false).
Given your situation you could have something similar to the following two methods, which you call depending on the signals you receive:
void OnRadioButton1()
{
lineEdit->setEnabled(false);
lineEdit2->setEnabled(true);
}
void OnRadioButton2()
{
lineEdit->setEnabled(true);
lineEdit2->setEnabled(false);
}
It's pretty straight-forward really. I don't understand where this whole notion of "real-time" comes into play. It's a single response to a single input "event".
Of course, this could just as well be a single method with a specific (boolean) argument or whatever. But given that we're discussing a hypothetical example case here that does not necessarily reflect your real code, this should at least provide you with a bit of an idea.
It is hard for me to understand the difference between signals and events in Qt, could someone explain?
An event is a message encapsulated in a class (QEvent) which is processed in an event loop and dispatched to a recipient that can either accept the message or pass it along to others to process. They are usually created in response to external system events like mouse clicks.
Signals and Slots are a convenient way for QObjects to communicate with one another and are more similar to callback functions. In most circumstances, when a "signal" is emitted, any slot function connected to it is called directly. The exception is when signals and slots cross thread boundaries. In this case, the signal will essentially be converted into an event.
Events are something that happened to or within an object. In general, you would treat them within the object's own class code.
Signals are emitted by an object. The object is basically notifying other objects that something happened. Other objects might do something as a result or not, but this is not the emitter's job to deal with it.
My impression of the difference is as follows:
Say you have a server device, running an infinite loop, listening to some external client Events and reacting to them by executing some code.
(It can be a CPU, listening to interrupts from devices, or Client-side Javascript browser code, litsening for user clicks or Server-side website code, listening for users requesting web-pages or data).
Or it can be your Qt application, running its main loop.
I'll be explaining with the assumption that you're running Qt on Linux with an X-server used for drawing.
I can distinguish 2 main differences, although the second one is somewhat disputable:
Events represent your hardware and are a small finite set. Signals represent your Widgets-layer logic and can be arbitrarily complex and numerous.
Events are low-level messages, coming to you from the client. The set of Events is a strictly limited set (~20 different Event types), determined by hardware (e.g. mouse click/doubleclick/press/release, mouse move, keyboard key pressed/released/held etc.), and specified in the protocol of interaction (e.g. X protocol) between application and user.
E.g. at the time X protocol was created there were no multitouch gestures, there were only mouse and keyboard so X protocol won't understand your gestures and send them to application, it will just interpret them as mouse clicks. Thus, extensions to X protocol are introduced over time.
X events know nothing about widgets, widgets exist only in Qt. X events know only about X windows, which are very basic rectangles that your widgets consist of. Your Qt events are just a thin wrapper around X events/Windows events/Mac events, providing a compatibility layer between different Operating Systems native events for convenience of Widget-level logic layer authors.
Widget-level logic deals with Signals, cause they include the Widget-level meaning of your actions. Moreover, one Signal can be fired due to different events, e.g. either mouse click on "Save" menu button or a keyboard shortcut such as Ctrl-S.
Abstractly speaking (this is not exactly about Qt!), Events are asynchronous in their nature, while Signals (or hooks in other terms) are synchronous.
Say, you have a function foo(), that can fire Signal OR emit Event.
If it fires signal, Signal is executed in the same thread of code as the function, which caused it, right after the function.
On the other hand, if it emits Event, Event is sent to the main loop and it depends on the main loop, when it delivers that event to the receiving side and what happens next.
Thus 2 consecutive events may even get delivered in reversed order, while 2 consecutively fired signals remain consecutive.
Though, terminology is not strict. "Singals" in Unix as a means of Interprocess Communication should be better called Events, cause they are asynchronous: you call a signal in one process and never know, when the event loop is going to switch to the receiving process and execute the signal handler.
P.S. Please forgive me, if some of my examples are not absolutely correct in terms of letter. They are still good in terms of spirit.
An event is passed directly to an event handler method of a class. They are available for you to overload in your subclasses and choose how to handle the event differently. Events also pass up the chain from child to parent until someone handles it or it falls off the end.
Signals on the other hand are openly emitted and any other entity can opt to connect and listen to them. They pass through the event loops and are processed in a queue (they can also be handled directly if they are in the same thread).