Jump to content

Wikipedia:Reference desk/Archives/Computing/2017 October 17

From Wikipedia, the free encyclopedia
Computing desk
< October 16 << Sep | October | Nov >> Current desk >
Welcome to the Wikipedia Computing Reference Desk Archives
The page you are currently viewing is an archive page. While you can leave answers for any questions shown below, please ask new questions on one of the current reference desk pages.


October 17[edit]

Dependency Inversion principle in OOP[edit]

A web programmer told me that the Dependency Inversion principle in OOP describes this:

In OOP design we usually go from outside (request) to the inside (response), from the view, to the model (by the controller CRUDing the model via view).

I have 2 questions regarding this:

1. Is this explanation of the principle accurate? Iא doesn't say why it specifically relates to the principle.

2. Why is "from the outer to the inner" is "inverted" in web?... I can't see why it would be inverted and not the other way around.

Anonymous.

We have an article Dependency inversion principle. The description you heard doesn't sound very accurate to me, but perhaps I'm not understanding it fully. Note by the way that the word "inversion" in this phrase is somewhat of a misnomer. Our article says "Nevertheless, the "inversion" concept does not mean that lower-level layers depend on higher-level layers." CodeTalker (talk) 17:17, 17 October 2017 (UTC)[reply]
Yes, sorry not to mention, the last thing you wrote about what I can call "dependency bidirectionality" was also reminded by the programmer. Thank you. Anonynous. — Preceding unsigned comment added by 79.180.1.206 (talk) 01:07, 18 October 2017 (UTC)[reply]

C structs[edit]

hello, is it allowed to cast a struct A*, say, as struct B*, and vice versa, if struct B has struct A as its very first member?
I want to do something like this:

Extended content
#include <malloc.h>

struct node_ {
	struct node_ *next;
};


struct my_int {
	struct node_ link;
	int data;
 };

struct my_float {
	struct node_ link;
	float data;
};

struct my_int *head=NULL;
struct my_float *head2=NULL;

struct my_int *new_int(int a){
	struct my_int *p=(struct my_int*) malloc(sizeof(struct my_int));
	p->data=a;
	p->link.next=NULL;
	return p;
}

struct my_float *new_float(float a){
	struct my_float *p=(struct my_float*) malloc(sizeof(struct my_float));
	p->data=a;
	p->link.next=NULL;
	return p;
}


void insert(void *a, void *b){
	struct node_** p=(struct node_**)a;
	struct node_ *q=(struct node_*)b;
	q->next=*p;
	*p=q;
}

int main(void){

	insert(&head,new_int(17));
	insert(&head,new_int(18));
	insert(&head,new_int(19));

	insert(&head2,new_float(3.14));
	insert(&head2,new_float(17.2));
	insert(&head2,new_float(19.1));

		
	for(struct my_int *p=head;p!=NULL;p=(struct my_int*)p->link.next){
		printf("%d\n",((struct my_int*)p)->data); 
	} 

	for(struct my_float *p=head2;p!=NULL;p=(struct my_float*)p->link.next){
		printf("%f\n",((struct my_float*)p)->data); 
	} 
	
	return 0;
}

this compiles, and works, but I'm not sure it's kosher. TIA 78.50.125.206 (talk) 20:35, 17 October 2017 (UTC)[reply]

Yes, that is safe, as the first item will be aligned to the beginning of each struct. But there is another weak point in your code: you do not check if malloc() returns a valid pointer! If p becomes NULL, an assignment to p->data will most probably end with a crash. --CiaPan (talk) 20:59, 17 October 2017 (UTC)[reply]
thank you! regarding malloc(3), most I could do is print a message and exit, but when the system's at a point where it can't accomodate memory requests for 20-odd bytes, there's no guarantee it can printf() (and especially, sprintf()) either. So letting it crash with a "core dumped" message would actually be more meaningful... 78.50.125.206 (talk) 09:08, 18 October 2017 (UTC)[reply]
There are reasons other than memory exhaustion that malloc() can fail. For instance, many systems allow the available memory of a process to be limited. Of course this all depends on the problem domain. If this is just a toy program, who cares? But if this is part of a larger program, and you want to be well-behaved, always check malloc. (Personally, I think it's a good thing to do anyway. That way you develop the habit of always doing the Right Thing.) On a related note, malloc.h is a non-standard glibc header. The standard C header containing malloc() is stdlib.h. (Again, fine if you want your program to depend on glibc, but I don't know if you do.) Also, you didn't include stdio.h for printf(). Finally, you didn't free() what you malloc()ed. (The same goes for this as for malloc().) --47.138.160.139 (talk) 22:58, 18 October 2017 (UTC)[reply]
Thought that occurred later: if you're new to C programming, a good self-teaching practice is to enable warnings in your compiler, and disable optimizations and compiler extensions. On GCC, I suggest at least -std=c99 -O0 -Wall -Wextra -Wpedantic. Then fix your code to not generate warnings. This will teach you things you might have overlooked, or didn't know were Bad Things or non-standard compiler extensions. Compiler extensions are not inherently bad, but you should be aware you're relying on them. And if you're wondering about optimizations, they can obscure bugs in your code. For instance, the compiler might optimize away code containing a runtime error. --47.138.160.139 (talk) 05:31, 19 October 2017 (UTC)[reply]
POSIX does say that these functions may fail with ENOMEM, but I don't think that happens in practice except perhaps for the first print to a new stream (which might allocate the output buffer for the FILE). (I also agree with 47's library discipline ideas.) --Tardis (talk) 02:53, 19 October 2017 (UTC)[reply]
Could you, please, tell me where I said you should print anything? AFAIR I only said you should check the value returned by malloc(). Accessing memory at NULL will most probably end with crash in most of popular environments, but that is not guaranteed! The way of handling the unexpected situation is up to you, but it's always better to do that explicitly. You can simply return NULL from your function and allow the caller to decide whether it wants to invoke a crash, end a process with an error status or possibly recover from the condition in some other manner.
For example:
struct my_float *new_float(float a){
	if( struct my_float *p=(struct my_float*) malloc(sizeof(struct my_float)) ) {
		p->data=a;
		p->link.next=NULL;
		return p;
	}
	return NULL;
}


void insert(void *a, void *b){
	if( b ) {
		struct node_** p=(struct node_**)a;
		struct node_ *q=(struct node_*)b;
		q->next=*p;
		*p=q;
	}
}
CiaPan (talk) 17:29, 22 October 2017 (UTC)[reply]