Overloading == and !== when object is a pointer - pointers

I am new to writing operators (in this case == and !=). I have done a bit of research and so far came up with:
bool operator==(const SPECIAL_EVENT_S &rsEvent)
{
bool bSame = false;
if (rsEvent.datEvent == m_datSpecialEvent &&
rsEvent.strEvent == m_strNotes &&
rsEvent.strLocation == m_strLocation &&
rsEvent.datEventStartTime == m_datEventStartTime &&
rsEvent.datEventFinishTime == m_datEventFinishTime &&
gsl::narrow<bool>(rsEvent.bEventAllDay) == m_bEventAllDay &&
gsl::narrow<bool>(rsEvent.bSetReminder) == m_bSetReminder &&
rsEvent.iReminderUnitType == m_iReminderUnitType &&
rsEvent.iReminderInterval == m_iReminderInterval &&
rsEvent.iImageWidthPercent == m_wImageWidthPercent &&
rsEvent.strImagePath == m_strImagePath &&
rsEvent.strTextBeforeImage == m_strTextBeforeImage &&
rsEvent.strTextAfterImage == m_strTextAfterImage &&
rsEvent.eType == m_eVideoconfType &&
rsEvent.sBSSTI == m_sBSSTI)
{
// The fundamental information is unchanged
bSame = true;
}
// Now compare the MWB Event Type
if (bSame)
{
switch (rsEvent.eMWBEventType)
{
case EventTypeMWB::MWBBethelSpeakerServiceTalk:
return m_bSpecialEventBethelServiceTalk;
case EventTypeMWB::MWBVideoconferenceAssembly:
return m_bSpecialEventVideoconf && m_eVideoconfType == VideoConferenceEventType::Live;
case EventTypeMWB::MWBVideoconferenceConvention:
return m_bSpecialEventVideoconf && m_eVideoconfType == VideoConferenceEventType::Recorded;
case EventTypeMWB::MWBSpecialEvent:
return m_bSpecialEvent;
case EventTypeMWB::MWBMemorial:
return m_bEventMemorial;
case EventTypeMWB::MWBCircuitOverseerMeeting:
return m_bCircuitVisit || m_bCircuitVisitGroup;
case EventTypeMWB::MWBMeeting:
return !m_bNoMeeting;
default:
bSame = false;
}
}
return bSame;
}
bool operator!=(const SPECIAL_EVENT_S& rsEvent)
{
return !(rsEvent == *this);
}
What surprised me what when I then tried to use these operators:
if (pEntry != sEvent)
{
AfxMessageBox(_T("The special event information has changed"));
}
It does not like pEntry being a pointer. In the end I did this:
if (*pEntry != sEvent)
{
AfxMessageBox(_T("The special event information has changed"));
}
Why was this an issue in the first place? I ask that because if this was a standard function it would not matter if the object was a pointer or not.
What is the correct way to cater for this scenario?
For example:
object->Function(value)
object.Function(value)
Function can be used both by the object when it is / is not a pointer. So why not with an operator?

Function can be used both by the object when it is / is not a pointer.
Actually, no it can't. In a statement/expression like object->Function(value) the -> (member access) and () (function call) operators have the same precedence and left-to-right associativity. So, the -> is applied first and that automatically dereferences the pointer. So, the effect is the same as (*object).Function(value) – and Function is still being called on an object, rather than on a pointer.
So why not with an operator?
The syntax for calling an operator function is (or can be) rather different: because it is defined as an operator, you can call it using the operator token (between the two operands) rather than by using an explicit function call. But then, you have to pass objects, as that's what the operands are defined to be.
However, should you really want to, you can still call an operator override using explicit function-call syntax; and, in that case, you can use the -> on a pointer; like this (where operator== is effectively the 'name' of the function):
if (!pEntry->operator==(sEvent))
{
AfxMessageBox(_T("The special event information has changed"));
}
However, this seems like a lot of hard work and your *pEntry != sEvent is actually the 'correct' way to use the override.
PS: As bonus, if you're using a compiler that supports the C++20 (or later) Standard, you can add a "defaulted" operator== to your structures/classes, which would save you explicitly comparing each individual data member:
struct foo {
int a;
double b;
bool operator==(const foo&) const = default; // Compares "a" and "b"
};
struct bar {
foo f;
int c;
int d;
bool operator==(const bar&) const = default; // Compares "c", "d" and "f"
};

Related

How can I determine if an Array is readonly using TS compiler-api?

I'd like to determine if an array type is readonly. This includes ReadonlyArray and readonly prefixed.
Examples:
type a = ReadonlyArray<string>
type b = readonly string[]
The relevant non-exposed TypeChecker code is:
let globalReadonlyArrayType = <GenericType>getGlobalTypeOrUndefined("ReadonlyArray" as __String, /*arity*/ 1) || globalArrayType;
function isReadonlyArrayType(type: Type): boolean {
return !!(getObjectFlags(type) & ObjectFlags.Reference) && (<TypeReference>type).target === globalReadonlyArrayType;
}
function getGlobalTypeOrUndefined(name: __String, arity = 0): ObjectType | undefined {
const symbol = getGlobalSymbol(name, SymbolFlags.Type, /*diagnostic*/ undefined);
return symbol && <GenericType>getTypeOfGlobalSymbol(symbol, arity);
}
function getTypeOfGlobalSymbol(symbol: Symbol | undefined, arity: number): ObjectType {
function getTypeDeclaration(symbol: Symbol): Declaration | undefined {
const declarations = symbol.declarations;
for (const declaration of declarations) {
switch (declaration.kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
return declaration;
}
}
}
if (!symbol) {
return arity ? emptyGenericType : emptyObjectType;
}
const type = getDeclaredTypeOfSymbol(symbol);
if (!(type.flags & TypeFlags.Object)) {
error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_be_a_class_or_interface_type, symbolName(symbol));
return arity ? emptyGenericType : emptyObjectType;
}
if (length((<InterfaceType>type).typeParameters) !== arity) {
error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbolName(symbol), arity);
return arity ? emptyGenericType : emptyObjectType;
}
return <ObjectType>type;
}
TypeChecker Method
cspotcode pointed out that you can get IndexInfo via the TypeChecker.
const isReadonlyArrayType = (type: Type) =>
type.checker.isArrayLikeType(type) &&
!!type.checker.getIndexInfoOfType(type, IndexKind.Number)?.isReadonly
TS Compiler Method
The following matches the compiler's logic.
let globalReadonlyArrayType: Type;
export const isReadonlyArrayType = (type: Type): boolean => {
const { checker } = type;
if (!globalReadonlyArrayType) {
const symbol =
checker.resolveName('ReadonlyArray', /* location */ void 0, SymbolFlags.Type, /* excludeGlobals */ false)!;
globalReadonlyArrayType = checker.getDeclaredTypeOfSymbol(symbol);
}
return !!((type as ObjectType).objectFlags & ObjectFlags.Reference) &&
((<TypeReference>type).target === globalReadonlyArrayType);
};
Notes
It appears that there may be no immediate advantage of the TypeChecker method over using the Compiler method. The one concern that I had was that comparing target equality may fail if ReadonlyArray was extended, but it appears that this is currently not possible with TypeScript (v3.9.3)
Logic-wise, if performing isArrayLikeType first, the TypeChecker method would be performing a little more work, but likely not enough to worry about in terms of performance.
With that said, it seems that there may be advantage in the TypeChecker method over the second in the event that TS changes its readonly logic, allows extension of ReadonlyArray, etc.
For that reason, I'd recommend using the TypeChecker method.
If you're not using byots, you could probably replace the call to isArrayLikeType with !!((type as ObjectType).objectFlags & ObjectFlags.Reference)
Caveat: My understanding of ReadonlyArray is at a basic level, as of writing this, so if I'm wrong on any of this, please let me know!

Function to check whether a binary tree is binary search tree or not?

I attempted writing the following method which tells whether a Binary Tree is Binary Search Tree or not? I pass only half of the test cases. What am I doing wrong?
boolean checkBST(Node root) {
boolean leftflag = false;
boolean rightflag = false;
Node l = root.left;
Node r = root.right;
if(l!=null) {
if(root.data <= l.data) {
leftflag = false;
}
else {
leftflag = true;
checkBST(l);
}
}
if(leftflag == false)
return false;
if(r != null) {
if(root.data >= r.data) {
rightflag = false;
}
else {
rightflag = true;
checkBST(r);
}
}
if(rightflag == false)
return false;
return true;
}
I can see a case where your program could return wrongly false.
Imagine you have a tree with 3 branches deep going as follow :
7
/ \
3 8
\ / \
4 6 9
Your program starts up at 7 (root), creates two boolean at false (leftflag and rightflag), checks if left is null. It isn't. It then checks if the data of left <= the data of right. It is.
So you recursively call your function with a new root node left (3 in the example). Again, it creates your two boolean at false initial value, checks if left node is null. It is ! So it skips the whole if, goes directly to your other if before the return.
// The condition here is respected, there is no left node
// But the tree is an actual search tree, you didn't check right node
// Before returning false.
if(leftflag == false)
return false
What i'd do is
if(l != null)
{
if(root.data<=l.data)
{
return false;
}
else
{
// recursive call here
}
}
if(r != null)
{
// Same as left node here
}
so even if your left node is null, the program still checks for the right node. Hope i helped out a little bit !
Your primary mistake is that you ignore the return value of your recursive calls. For instance:
else {
leftflag = true;
checkBST(l);
}
}
if(leftflag == false)
return false;
If checkBST(l) returns false, you ignore it. You never save the value. Thus, your subsequent check for leftflag is utterly ignorant of the subtree's suitability. Semantically, your routine assumes that all subtrees are BSTs -- you set the flag, recur on the subtree, but don't change the flag. Try this logic:
else
leftflag = checkBST(l)
Now, please get comfortable with Boolean expressions. For instance, testing a Boolean value against a Boolean constant is a little wasteful. Instead of
if (flag == false)
Just check directly:
if (!flag)
Checking a pointer for null is similar in most languages:
if (l)
Finally, don't initialize your flags if you're simply going to set them to the same value as the first action.
Now, your code might appear like this:
boolean leftflag = false;
boolean rightflag = false;
if(l) {
if(root.data > l.data) {
leftflag = checkBST(l);
}
}
if(!leftflag)
return false;
if(r) {
if(root.data < r.data) {
rightflag = checkBST(r);
}
}
if(rightflag == false)
return false;
return true;
}
Now it's a little easier to follow the logic flow. Note that you have a basic failure in your base case: a null tree is balanced, but you return false.
Now, if you care to learn more about logic short-circuiting and boolean expressions, you can reduce your routine to something more like this:
return
(!root.left || // Is left subtree a BST?
(root.data > root.left.data &&
checkBST(root.left)))
&&
(!root.right || // Is right subtree a BST?
(root.data > root.right.data &&
checkBST(root.right)))

Additional return statement while finding minimum depth of a Binary Search Tree

Following is the code that I found online to find the minimum depth of a binary search tree:
public class Solution {
public int minDepth(TreeNode root) {
if(root == null){
return 0;
}
LinkedList<TreeNode> nodes = new LinkedList<TreeNode>();
LinkedList<Integer> counts = new LinkedList<Integer>();
nodes.add(root);
counts.add(1);
while(!nodes.isEmpty()){
TreeNode curr = nodes.remove();
int count = counts.remove();
if(curr.left != null){
nodes.add(curr.left);
counts.add(count+1);
}
if(curr.right != null){
nodes.add(curr.right);
counts.add(count+1);
}
if(curr.left == null && curr.right == null){
return count;
}
}
return 0;
}
}
What I do not understand is the extra return statement at the end- return 0. Why is this needed?
It's for the case where the root isn't null, but it's the only node in the tree (the root is at depth 0). That return statement is needed because if the tree is empty, then something must be returned. It returns 0, because the depth is 0.
Similar to ghostofrasputin, the return statement is there because if the while condition is not met, then there is still a value to return.
Now the more important question, why do we need the last return if the program will never reach that return statement? (which I believe is this case for this)
Even though you are able to tell that the return statement wont be used, the compiler is not sophisticated enough to determine that, so it requires a return statement just in case the while loop is exited.
It's similar to the following code
public boolean getTrueOrFalse() {
if(Math.random() < 1) {
return true;
}
return false;
}
Though we know that this will always return true because Math.random() is always less than 1, the compiler isn't able to figure that out and thus the return statement is required if the if-statement is not met.

how to write mutually recursive functions in Haxe

I am trying to write a simple mutually recursive function in Haxe 3, but couldn't get the code to compile because whichever one of the mutual functions that appears first will report that the other functions in the group is undefined. A minimal example is below, in which mutually defined functions odd and even are used to determine parity.
static public function test(n:Int):Bool {
var a:Int;
if (n >= 0) a = n; else a = -n;
function even(x:Int):Bool {
if (x == 0)
return true;
else
return odd(x - 1);
}
function odd(x:Int):Bool {
if (x == 0)
return false;
else
return even(x - 1);
}
return even(a);
}
Trying to compile it to neko gives:
../test.hx:715: characters 11-14 : Unknown identifier : odd
Uncaught exception - load.c(181) : Module not found : main.n
I tried to give a forward declaration of odd before even as one would do in c/c++, but it seems to be illegal in haxe3. How can one define mutually-recursive functions like above? Is it possible at all?
Note: I wanted to have both odd and even to be local functions wrapped in the globally visible function test.
Thanks,
Rather than using the function myFn() {} syntax for a local variable, you can use the myFn = function() {} syntax. Then you are able to declare the function type signiatures before you use them.
Your code should now look like:
static public function test(n:Int):Bool {
var a:Int;
if (n >= 0) a = n; else a = -n;
var even:Int->Bool = null;
var odd = null; // Leave out the type signiature, still works.
even = function (x:Int):Bool {
if (x == 0)
return true;
else
return odd(x - 1);
}
odd = function (x:Int):Bool {
if (x == 0)
return false;
else
return even(x - 1);
}
return even(a);
}
This works because Haxe just needs to know that even and odd exist, and are set to something (even if it's null) before they are used. We know that we'll set both of them to callable functions before they are actually called.
See on try haxe: http://try.haxe.org/#E79D4

What is the different between stringvariable != NullValue.String and !string.IsNullOrEmpty(stringvariable) in asp.net?

Is there any different between stringvariable != NullValue.String and !string.IsNullOrEmpty(stringvariable) in asp.net ? then which is best ?
The first tests that the string isn't "".
As strings can be null (because they are actually references) this test could fail.
By using IsNullOrEmpty you are wrapping:
if (string != null && string.Length > 0)
in one test.
IsNullOrEmpty is implemented like:
public static bool IsNullOrEmpty(string value)
{
if (value != null)
{
return (value.Length == 0);
}
return true;
}
So it checks both an empty string, and a null string. (Where is NullValue.String defined, I cannot seem to find a reference to it in any docs, but I assume it's eiter String.Empty or "null", so your first check only checks for one of these conditions.)
.Net4 has a new function called IsNullOrWhiteSpace(string value) which also returns true if the string contains only white space.

Resources