Re: Good Use of GOTO

new topic     » goto parent     » topic index » view thread      » older message » newer message

Jim Brown wrote:
> 
> c.k.lester wrote:
> > 
> > After hearing from both sides, I've come to the conclusion that the goto
> > being implemented is unnecessary. We are getting loop constructs that
> > handle most of what GOTO would be used for, aren't we?
> > 
> >    continue, exit, retry, etc...
> > 
> > These all lend themselves to maintenance, program flow, structure, while a
> > GOTO does not.
> > 
> > Can somebody show me a case (with sample code) where a GOTO would be
> > significantly better than using another construct? Also, please explain
> > why Euphoria would need GOTO if we add PCRE to the interpreter.
> 
> How would you implement/rewrite the following functions (from Linux kernel
> 2.6.11
> source) ? Even if you had the full repretiore of eu 4.0 keywords? (which,
> admittedly,
> the author of this code did not have)
> 
> static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
>                                   struct nameidata *nd)
> {       
>         int res;
>         struct vfat_slot_info sinfo;
>         struct inode *inode;
>         struct dentry *alias;
>         struct buffer_head *bh = NULL
>         struct msdos_dir_entry *de;
>         int table;
> 
>         lock_kernel();
>         table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0;
>         dentry->d_op = &vfat_dentry_ops[table];
> 
>         inode = NULL;
>         res = vfat_find(dir, &dentry->d_name, &sinfo, &bh, &de);
>         if (res < 0) {
>                 table++;
>                 goto error;
>         }
>         inode = fat_build_inode(dir->i_sb, de, sinfo.i_pos, &res);
>         brelse(bh);        if (res) {
>                 unlock_kernel();
>                 return ERR_PTR(res);
>         }
>         alias = d_find_alias(inode);
>         if (alias) {
>                 if (d_invalidate(alias) == 0)
>                         dput(alias);
>                 else {  
>                         iput(inode);
>                         unlock_kernel();
>                         return alias;
>                 }
>         
>         }
> error:  
>         unlock_kernel();
>         dentry->d_op = &vfat_dentry_ops[table];
>         dentry->d_time = dentry->d_parent->d_inode->i_version;
>         dentry = d_splice_alias(inode, dentry);               
>         if (dentry) {                                         
>                 dentry->d_op = &vfat_dentry_ops[table];
>                 dentry->d_time = dentry->d_parent->d_inode->i_version;
>         }
>         return dentry;
> }
> 
> static int vfat_create(struct inode *dir, struct dentry *dentry, int mode,
>                        struct nameidata *nd)
> {
>         struct super_block *sb = dir->i_sb;
>         struct inode *inode = NULL;
>         struct buffer_head *bh = NULL;
>         struct msdos_dir_entry *de;
>         struct vfat_slot_info sinfo;
>         int res;
> 
>         lock_kernel();
>         res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de);
>         if (res < 0)
>                 goto out;
>         inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
>         brelse(bh);
>         if (!inode)
>                 goto out;
>         res = 0;
>         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
>         mark_inode_dirty(inode);
>         inode->i_version++;
>         dir->i_version++;
>         dentry->d_time = dentry->d_parent->d_inode->i_version;
>         d_instantiate(dentry, inode);
> out:
>         unlock_kernel();
>         return res;
> }
> 
> static int vfat_build_slots(struct inode *dir, const unsigned char *name,
>                             int len, struct msdos_dir_slot *ds,
>                             int *slots, int is_dir)
> {       
>         struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
>         struct fat_mount_options *opts = &sbi->options;
>         struct msdos_dir_slot *ps;
>         struct msdos_dir_entry *de;
>         unsigned long page;
>         unsigned char cksum, lcase;
>         unsigned char msdos_name[MSDOS_NAME];
>         wchar_t *uname;
>         int res, slot, ulen, usize, i;
>         loff_t offset;
> 
>         *slots = 0;
>         res = vfat_valid_longname(name, len);
>         if (res)
>                 return res;
> 
>         page = __get_free_page(GFP_KERNEL);
>         if (!page)
>                 return -ENOMEM;                               
> 
>         uname = (wchar_t *)page;
>         res = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
>                            opts->unicode_xlate, opts->utf8, sbi->nls_io);
>         if (res < 0)
>                 goto out_free;
>         
>         res = vfat_is_used_badchars(uname, ulen);
>         if (res < 0) 
>                 goto out_free;
>         
>         res = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen,
>                                     msdos_name, &lcase);
>         if (res < 0) 
>                 goto out_free;
>         else if (res == 1) { 
>                 de = (struct msdos_dir_entry *)ds;
>                 res = 0;
>                 goto shortname;                               
>         }                                                     
> 
>         /* build the entry of long file name */
>         *slots = usize / 13;
>         for (cksum = i = 0; i < 11; i++)
>                 cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];
>         
>         for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {
>                 ps->id = slot;
>                 ps->attr = ATTR_EXT;
>                 ps->reserved = 0;
>                 ps->alias_checksum = cksum;
>                 ps->start = 0; 
>                 offset = (slot - 1) * 13;
>                 fatwchar_to16(ps->name0_4, uname + offset, 5);
>                 fatwchar_to16(ps->name5_10, uname + offset + 5, 6);
>                 fatwchar_to16(ps->name11_12, uname + offset + 11, 2);
>         }
>         ds[0].id |= 0x40;
>         de = (struct msdos_dir_entry *)ps;
> 
> shortname: 
>         /* build the entry of 8.3 alias name */
>         (*slots)++;
>         memcpy(de->name, msdos_name, MSDOS_NAME);
>         de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
>         de->lcase = lcase;
>         de->adate = de->cdate = de->date = 0;
>         de->ctime = de->time = 0;
>         de->ctime_ms = 0;
>         de->start = 0;
>         de->starthi = 0;
>         de->size = 0;
> 
> out_free:
>         free_page(page);
>         return res;
> }
My official vote was "abstain", but I took this as a personal challenge. Plus,
it sounded fun.

Now, this is actually two functions and I've only done one so far. Note: I don't
think most arguments apply to this first function, especially "don't repeat
yourself" or whether the thing is maintainable or not. Heck, I think that this
piece of C code could probably use goto far better than it has done, but the
challenge wasn't to rewrite this piece of code in C.

-- let's assume that all structs, pointers to structs, and references are
actually sequences.

function vfat_lookup(sequence dir_p, sequence dentry_p, sequence nd_p)
	integer res
	sequence sinfo
	sequence inode_p
	sequence alias_p
	sequence bh_p
	sequence de_p
	integer table
	object tmp

	lock_kernel()
	tmp = msdos_sb(dir_p[I_SB])
	tmp = tmp[OPTIONS[NAME_CHECK]]
	if tmp = 's' then
		table = 2
	else
		table = 0
	end if
	dentry_p[D_OP] = vfat_dentry_ops[table]

	inode_p = {}
	res = vfat_find(dir_p, dentry_p[D_NAME], sinfo, bh_p, de_p)

	if res < 0 then
		table++
		-- error!
	else
		while 1 do -- I don't usually code this way...
		inode_p = fat_build_inode(dir_p[I_SB], de_p, sinfo[I_POS], res)
		brelse(bh_p)	if res then
			unlock_kernel()
			return err_ptr(res)
		end if
		alias = d_find_alias(inode_p)
		if length(alias) > 0 then
			if d_invalidate(alias) = 0 then
				dput(alias)
			else
				iput(inode_p)
				unlock_kernel()
				return alias
			end if
		end if

		exit -- error!
		end while
	end if
        
	-- error!
	unlock_kernel()
	dentry_p[D_OP] = vfat_dentry_ops[table]
	dentry_p[D_TIME] = dentry[D_PARENT][D_INODE][I_VERSION]
	dentry_p = d_splice_alias(inode_p, dentry_p)
	if length(dentry_p) > 0 then
		dentry_p[D_OP] = vfat_dentry_ops[table]
		dentry_p[D_TIME] = dentry_p[D_PARENT][D_INODE][I_VERSION]
	end if
	return dentry_p

end function


(once again wishing euforum had a preview mode so I don't look too foolish)

--
A complex system that works is invariably found to have evolved from a simple
system that works.
--John Gall's 15th law of Systemantics.

"Premature optimization is the root of all evil in programming."
--C.A.R. Hoare

j.

new topic     » goto parent     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu