Re: Good Use of GOTO
- Posted by Jason Gade <jaygade at y?hoo?com> Jun 06, 2008
- 856 views
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.